Why no overflows with native tokens?

This question is a bit theoretical. With compility versions higher than 8 an overflow can no longer happen on a token as in the following contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract Token {

  mapping(address => uint) balances;
  uint public totalSupply;

  constructor(uint _initialSupply) public {
    balances[msg.sender] = totalSupply = _initialSupply;

  function transfer(address _to, uint _value) public returns (bool) {
    require(balances[msg.sender] - _value >= 0);
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    return true;

  function balanceOf(address _owner) public view returns (uint balance) {
    return balances[_owner];

But that got me thinking about why the same thing didn't happen with a native token. If we transfer an amount higher than our balance, an overflow never happens. On the other hand, with tokens created by us, it could happen without the appropriate security measures.

Why didn't it happen with native tokens?