State Types

The only requirement for a class to be used as a state in this system is to implement IState, which means that states can be anything you want: MonoBehaviour components attached to a scene object or prefab, ScriptableObject assets in the project, or just regular C# classes. But rather than implementing the entire interface from scratch every time, there are several base classes that can make your implementation simpler:

Class Description
StateBehaviour

Inherits from MonoBehaviour and implements IState to act as the base class for states that are attached as components on GameObjects. Its OnEnterState and OnExitState methods enable and disable itself respectively, allowing you to use the regular MonoBehaviour Messages like OnEnable and OnDisable to implement your state transition logic, as well as other messages like Update or FixedUpdate depending on the needs of each individual state.

All of the State Machines examples after Game Manager use State Behaviours.
State

A basically empty class which implements IState using virtual members (the Can... properties return true and the On... methods do nothing) so that when you Inherit from it you only need to override the members you actually want to use.

The GameManagerFSM.State class from the Game Manager example inherits from this State since the only member it actually needs to override is OnEnterState.
DelegateState Implements IState, but rather than defining its own logic it simply has a Delegate for each of the members of that interface so you can assign them when creating the state.

Owned States

States do not need a reference to the StateMachine they are used in for the system to function, however this makes them slightly less convenient to use so if your state type implements IOwnedState (which inherits from IState) then you can use the Extension Methods in the StateExtensions class with your states. For example:

public abstract class CharacterState : StateBehaviour, IOwnedState<CharacterState>
{
    [SerializeField]
    private Character _Character;
    public Character Character => _Character;

    // Implement the OwnerStateMachine property from IOwnedState<CharacterState>:
    public StateMachine<CharacterState> OwnerStateMachine => _Character.StateMachine;

}

public class Character : MonoBehaviour
{
    [SerializeField]
    private CharacterState _Idle;
    public CharacterState Idle => _Idle;

    [SerializeField]
    private CharacterState _Walk;
    public CharacterState Walk => _Walk;

    public StateMachine<CharacterState> StateMachine { get; private set; }

    private void Awake()
    {
        // Initialize the FSM to start in the Idle state.
        StateMachine = new StateMachine<CharacterState>(_Idle);
    }
}

public class CharacterBrain : MonoBehaviour
{
    [SerializeField]
    private Character _Character;

    private void Update()
    {
        if (Input.GetKey(KeyCode.W))
        {
            // Normally we would need to tell the StateMachine which state to enter.
            // Note how we have to repeat "_Character" twice.
            _Character.StateMachine.TrySetState(_Character.Walk);

            // But since CharacterState implements IOwnedState we can do the same thing with:
            _Character.Walk.TryEnterState();
        }
    }

    private bool IsWalking()
    {
        // Normally we repeat "_Character" twice:
        return _Character.StateMachine.CurrentState == _Character.Walk;

        // But with an IOwnedState we don't need to:
        return _Character.Walk.IsCurrentState();
    }
}