Concept: Storage Model

There are two persistent backends plus one generic store. Choosing the right one is about scope - is a value tied to this machine, or to the player's account?

BackendBaseScopeUse for
UCrimsonSettingsLocalUGameUserSettings (GameUserSettings.ini)This machineHardware-coupled state: resolution, scalability, gamma, frame pacing. Reached via UCrimsonSettingsLocal::Get().
UCrimsonSettingsSharedULocalPlayerSaveGame (save slot)This player (follows the account)Player taste: audio, sensitivity, camera options, accessibility. Loaded via LoadOrCreateSettings(LocalPlayer).
Keyed storeA TMap on UCrimsonSettingsSharedThis playerThe generic Key -> value bag that Persist To Shared Store writes to - no typed field needed.

The keyed store + subsystem

UCrimsonSettingsShared holds a generic Key -> value map and typed accessors (Get/Set Float/Int/Bool/String Value, Has Keyed Value). It is stored as strings (scalar = number, discrete = index) - the same format the profile system uses - so any value round-trips. Writing a key marks the save dirty and broadcasts OnSettingChanged.

UCrimsonSharedSettingsSubsystem (a ULocalPlayerSubsystem) owns the per-player UCrimsonSettingsShared at runtime: it loads it, exposes it via GetSharedSettings(), and flushes SaveSettings() on a short debounce whenever a value changes. Always reach the shared object through the subsystem - there is no global singleton.

Why this decouples plugins
Because the store is opaque, adding a new persistent setting never touches CrimsonSettings' source. Any plugin (or your game) authors an entry with a StorageKey and reads it back by name. That is the mechanism behind How-To: Expose Another Plugin's Settings.
Multiplayer
Settings are a client-owned presentation/preference concern. UCrimsonSettingsShared can be made available server-side for authority checks where a preference affects gameplay, but the screen and the keyed store run on the owning client. Don't drive authoritative gameplay from a client's preference value.