You got most of it correct tbh except for the Character inheritance stuff.
You should aim for Characters to be all-purpose and not specific to a particular Game Mode. That way, you can easily switch Game Modes without having to make a new Character.
If you absolutely require per-Game Mode capabilities that you don’t think should always be allowed on the player, then it may be better to let the Game Mode add a Component to the Character that provides the player with those additional capabilities. In this case, composition always beats inheritance.
Game Mode: defines the game rule set and processes those rules.
Game State: stores the current game-wide state (shouldn’t really do any logic. It’s mainly for replication purposes).
Player State: stores player-specific state (shouldn’t really do any logic. It’s mainly for replication purposes).
Player Character: the living state and capabilities of the player. (By living state, I mean this state should be considered transient and will be wiped out upon death).
Player Controller: handles input and stores sensitive information between client and server. Is also used to allow the client to directly communicate to the server via RPCs (since it’s the only thing out-of-the-box that the client actually owns).
Game Instance: kinda like engine-game state. It’s mostly useless but there’s some use cases. Usually used for managing local players, but no one really cares about split screen anymore.
The utilisation of these objects only really matters for arena-style multiplayer games, like the ones you mentioned. For single player games or those that play much more differently, these objects are mostly irrelevant and if anything, will just get in your way.