diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
index f41d7bdbfa..9b08f008d1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
@@ -172,7 +172,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
 
     override fun onUserLeaveHint() {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
-            if (BooleanSetting.PICTURE_IN_PICTURE.boolean && !isInPictureInPictureMode) {
+            if (BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && !isInPictureInPictureMode) {
                 val pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
                     .getPictureInPictureActionsBuilder().getPictureInPictureAspectBuilder()
                 enterPictureInPictureMode(pictureInPictureParamsBuilder.build())
@@ -284,7 +284,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
 
     private fun PictureInPictureParams.Builder.getPictureInPictureAspectBuilder():
         PictureInPictureParams.Builder {
-        val aspectRatio = when (IntSetting.RENDERER_ASPECT_RATIO.int) {
+        val aspectRatio = when (IntSetting.RENDERER_ASPECT_RATIO.getInt()) {
             0 -> Rational(16, 9)
             1 -> Rational(4, 3)
             2 -> Rational(21, 9)
@@ -331,7 +331,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
             pictureInPictureActions.add(pauseRemoteAction)
         }
 
-        if (BooleanSetting.AUDIO_MUTED.boolean) {
+        if (BooleanSetting.AUDIO_MUTED.getBoolean()) {
             val unmuteIcon = Icon.createWithResource(
                 this@EmulationActivity,
                 R.drawable.ic_pip_unmute
@@ -376,7 +376,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
             val isEmulationActive = emulationViewModel.emulationStarted.value &&
                 !emulationViewModel.isEmulationStopping.value
             pictureInPictureParamsBuilder.setAutoEnterEnabled(
-                BooleanSetting.PICTURE_IN_PICTURE.boolean && isEmulationActive
+                BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && isEmulationActive
             )
         }
         setPictureInPictureParams(pictureInPictureParamsBuilder.build())
@@ -390,9 +390,13 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
                 if (!NativeLibrary.isPaused()) NativeLibrary.pauseEmulation()
             }
             if (intent.action == actionUnmute) {
-                if (BooleanSetting.AUDIO_MUTED.boolean) BooleanSetting.AUDIO_MUTED.setBoolean(false)
+                if (BooleanSetting.AUDIO_MUTED.getBoolean()) {
+                    BooleanSetting.AUDIO_MUTED.setBoolean(false)
+                }
             } else if (intent.action == actionMute) {
-                if (!BooleanSetting.AUDIO_MUTED.boolean) BooleanSetting.AUDIO_MUTED.setBoolean(true)
+                if (!BooleanSetting.AUDIO_MUTED.getBoolean()) {
+                    BooleanSetting.AUDIO_MUTED.setBoolean(true)
+                }
             }
             buildPictureInPictureParams()
         }
@@ -423,7 +427,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
             } catch (ignored: Exception) {
             }
             // Always resume audio, since there is no UI button
-            if (BooleanSetting.AUDIO_MUTED.boolean) BooleanSetting.AUDIO_MUTED.setBoolean(false)
+            if (BooleanSetting.AUDIO_MUTED.getBoolean()) {
+                BooleanSetting.AUDIO_MUTED.setBoolean(false)
+            }
         }
     }
 
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractBooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractBooleanSetting.kt
index aeda8d2220..0ba4653562 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractBooleanSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractBooleanSetting.kt
@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 
 interface AbstractBooleanSetting : AbstractSetting {
-    val boolean: Boolean
-
+    fun getBoolean(needsGlobal: Boolean = false): Boolean
     fun setBoolean(value: Boolean)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractByteSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractByteSetting.kt
index 606519ad84..cf63005359 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractByteSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractByteSetting.kt
@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 
 interface AbstractByteSetting : AbstractSetting {
-    val byte: Byte
-
+    fun getByte(needsGlobal: Boolean = false): Byte
     fun setByte(value: Byte)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractFloatSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractFloatSetting.kt
index 974925eeda..c6c0bcf348 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractFloatSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractFloatSetting.kt
@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 
 interface AbstractFloatSetting : AbstractSetting {
-    val float: Float
-
+    fun getFloat(needsGlobal: Boolean = false): Float
     fun setFloat(value: Float)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractIntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractIntSetting.kt
index 89b285b108..826402c343 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractIntSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractIntSetting.kt
@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 
 interface AbstractIntSetting : AbstractSetting {
-    val int: Int
-
+    fun getInt(needsGlobal: Boolean = false): Int
     fun setInt(value: Int)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractLongSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractLongSetting.kt
index 4873942db7..2b62cc06b5 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractLongSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractLongSetting.kt
@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 
 interface AbstractLongSetting : AbstractSetting {
-    val long: Long
-
+    fun getLong(needsGlobal: Boolean = false): Long
     fun setLong(value: Long)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractSetting.kt
index 8b6d29fe5b..e384c78c25 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractSetting.kt
@@ -7,12 +7,7 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
 
 interface AbstractSetting {
     val key: String
-    val category: Settings.Category
     val defaultValue: Any
-    val androidDefault: Any?
-        get() = null
-    val valueAsString: String
-        get() = ""
 
     val isRuntimeModifiable: Boolean
         get() = NativeConfig.getIsRuntimeModifiable(key)
@@ -20,5 +15,14 @@ interface AbstractSetting {
     val pairedSettingKey: String
         get() = NativeConfig.getPairedSettingKey(key)
 
+    val isSwitchable: Boolean
+        get() = NativeConfig.getIsSwitchable(key)
+
+    var global: Boolean
+        get() = NativeConfig.usingGlobal(key)
+        set(value) = NativeConfig.setGlobal(key, value)
+
+    fun getValueAsString(needsGlobal: Boolean = false): String
+
     fun reset()
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractShortSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractShortSetting.kt
index 91407ccbb4..8bfa81e4ac 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractShortSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractShortSetting.kt
@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 
 interface AbstractShortSetting : AbstractSetting {
-    val short: Short
-
+    fun getShort(needsGlobal: Boolean = false): Short
     fun setShort(value: Short)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractStringSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractStringSetting.kt
index c8935cc48c..6ff8fd3f9a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractStringSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractStringSetting.kt
@@ -4,7 +4,6 @@
 package org.yuzu.yuzu_emu.features.settings.model
 
 interface AbstractStringSetting : AbstractSetting {
-    val string: String
-
+    fun getString(needsGlobal: Boolean = false): String
     fun setString(value: String)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
index 8476ce8671..16f06cd0af 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
@@ -5,36 +5,34 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
-enum class BooleanSetting(
-    override val key: String,
-    override val category: Settings.Category,
-    override val androidDefault: Boolean? = null
-) : AbstractBooleanSetting {
-    AUDIO_MUTED("audio_muted", Settings.Category.Audio),
-    CPU_DEBUG_MODE("cpu_debug_mode", Settings.Category.Cpu),
-    FASTMEM("cpuopt_fastmem", Settings.Category.Cpu),
-    FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives", Settings.Category.Cpu),
-    RENDERER_USE_SPEED_LIMIT("use_speed_limit", Settings.Category.Core),
-    USE_DOCKED_MODE("use_docked_mode", Settings.Category.System, false),
-    RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache", Settings.Category.Renderer),
-    RENDERER_FORCE_MAX_CLOCK("force_max_clock", Settings.Category.Renderer),
-    RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders", Settings.Category.Renderer),
-    RENDERER_REACTIVE_FLUSHING("use_reactive_flushing", Settings.Category.Renderer, false),
-    RENDERER_DEBUG("debug", Settings.Category.Renderer),
-    PICTURE_IN_PICTURE("picture_in_picture", Settings.Category.Android),
-    USE_CUSTOM_RTC("custom_rtc_enabled", Settings.Category.System);
+enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
+    AUDIO_MUTED("audio_muted"),
+    CPU_DEBUG_MODE("cpu_debug_mode"),
+    FASTMEM("cpuopt_fastmem"),
+    FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives"),
+    RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
+    USE_DOCKED_MODE("use_docked_mode"),
+    RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache"),
+    RENDERER_FORCE_MAX_CLOCK("force_max_clock"),
+    RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
+    RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
+    RENDERER_DEBUG("debug"),
+    PICTURE_IN_PICTURE("picture_in_picture"),
+    USE_CUSTOM_RTC("custom_rtc_enabled");
 
-    override val boolean: Boolean
-        get() = NativeConfig.getBoolean(key, false)
+    override fun getBoolean(needsGlobal: Boolean): Boolean =
+        NativeConfig.getBoolean(key, needsGlobal)
 
-    override fun setBoolean(value: Boolean) = NativeConfig.setBoolean(key, value)
-
-    override val defaultValue: Boolean by lazy {
-        androidDefault ?: NativeConfig.getBoolean(key, true)
+    override fun setBoolean(value: Boolean) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setBoolean(key, value)
     }
 
-    override val valueAsString: String
-        get() = if (boolean) "1" else "0"
+    override val defaultValue: Boolean by lazy { NativeConfig.getDefaultToString(key).toBoolean() }
+
+    override fun getValueAsString(needsGlobal: Boolean): String = getBoolean(needsGlobal).toString()
 
     override fun reset() = NativeConfig.setBoolean(key, defaultValue)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ByteSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ByteSetting.kt
index 6ec0a765ef..7b7fac2112 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ByteSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ByteSetting.kt
@@ -5,21 +5,21 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
-enum class ByteSetting(
-    override val key: String,
-    override val category: Settings.Category
-) : AbstractByteSetting {
-    AUDIO_VOLUME("volume", Settings.Category.Audio);
+enum class ByteSetting(override val key: String) : AbstractByteSetting {
+    AUDIO_VOLUME("volume");
 
-    override val byte: Byte
-        get() = NativeConfig.getByte(key, false)
+    override fun getByte(needsGlobal: Boolean): Byte = NativeConfig.getByte(key, needsGlobal)
 
-    override fun setByte(value: Byte) = NativeConfig.setByte(key, value)
+    override fun setByte(value: Byte) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setByte(key, value)
+    }
 
-    override val defaultValue: Byte by lazy { NativeConfig.getByte(key, true) }
+    override val defaultValue: Byte by lazy { NativeConfig.getDefaultToString(key).toByte() }
 
-    override val valueAsString: String
-        get() = byte.toString()
+    override fun getValueAsString(needsGlobal: Boolean): String = getByte(needsGlobal).toString()
 
     override fun reset() = NativeConfig.setByte(key, defaultValue)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/FloatSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/FloatSetting.kt
index 0181d06f21..4644824d8a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/FloatSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/FloatSetting.kt
@@ -5,22 +5,22 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
-enum class FloatSetting(
-    override val key: String,
-    override val category: Settings.Category
-) : AbstractFloatSetting {
+enum class FloatSetting(override val key: String) : AbstractFloatSetting {
     // No float settings currently exist
-    EMPTY_SETTING("", Settings.Category.UiGeneral);
+    EMPTY_SETTING("");
 
-    override val float: Float
-        get() = NativeConfig.getFloat(key, false)
+    override fun getFloat(needsGlobal: Boolean): Float = NativeConfig.getFloat(key, false)
 
-    override fun setFloat(value: Float) = NativeConfig.setFloat(key, value)
+    override fun setFloat(value: Float) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setFloat(key, value)
+    }
 
-    override val defaultValue: Float by lazy { NativeConfig.getFloat(key, true) }
+    override val defaultValue: Float by lazy { NativeConfig.getDefaultToString(key).toFloat() }
 
-    override val valueAsString: String
-        get() = float.toString()
+    override fun getValueAsString(needsGlobal: Boolean): String = getFloat(needsGlobal).toString()
 
     override fun reset() = NativeConfig.setFloat(key, defaultValue)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
index ef10b209fd..21e4e1afd5 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
@@ -5,36 +5,33 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
-enum class IntSetting(
-    override val key: String,
-    override val category: Settings.Category,
-    override val androidDefault: Int? = null
-) : AbstractIntSetting {
-    CPU_BACKEND("cpu_backend", Settings.Category.Cpu),
-    CPU_ACCURACY("cpu_accuracy", Settings.Category.Cpu),
-    REGION_INDEX("region_index", Settings.Category.System),
-    LANGUAGE_INDEX("language_index", Settings.Category.System),
-    RENDERER_BACKEND("backend", Settings.Category.Renderer),
-    RENDERER_ACCURACY("gpu_accuracy", Settings.Category.Renderer, 0),
-    RENDERER_RESOLUTION("resolution_setup", Settings.Category.Renderer),
-    RENDERER_VSYNC("use_vsync", Settings.Category.Renderer),
-    RENDERER_SCALING_FILTER("scaling_filter", Settings.Category.Renderer),
-    RENDERER_ANTI_ALIASING("anti_aliasing", Settings.Category.Renderer),
-    RENDERER_SCREEN_LAYOUT("screen_layout", Settings.Category.Android),
-    RENDERER_ASPECT_RATIO("aspect_ratio", Settings.Category.Renderer),
-    AUDIO_OUTPUT_ENGINE("output_engine", Settings.Category.Audio);
+enum class IntSetting(override val key: String) : AbstractIntSetting {
+    CPU_BACKEND("cpu_backend"),
+    CPU_ACCURACY("cpu_accuracy"),
+    REGION_INDEX("region_index"),
+    LANGUAGE_INDEX("language_index"),
+    RENDERER_BACKEND("backend"),
+    RENDERER_ACCURACY("gpu_accuracy"),
+    RENDERER_RESOLUTION("resolution_setup"),
+    RENDERER_VSYNC("use_vsync"),
+    RENDERER_SCALING_FILTER("scaling_filter"),
+    RENDERER_ANTI_ALIASING("anti_aliasing"),
+    RENDERER_SCREEN_LAYOUT("screen_layout"),
+    RENDERER_ASPECT_RATIO("aspect_ratio"),
+    AUDIO_OUTPUT_ENGINE("output_engine");
 
-    override val int: Int
-        get() = NativeConfig.getInt(key, false)
+    override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
 
-    override fun setInt(value: Int) = NativeConfig.setInt(key, value)
-
-    override val defaultValue: Int by lazy {
-        androidDefault ?: NativeConfig.getInt(key, true)
+    override fun setInt(value: Int) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setInt(key, value)
     }
 
-    override val valueAsString: String
-        get() = int.toString()
+    override val defaultValue: Int by lazy { NativeConfig.getDefaultToString(key).toInt() }
+
+    override fun getValueAsString(needsGlobal: Boolean): String = getInt(needsGlobal).toString()
 
     override fun reset() = NativeConfig.setInt(key, defaultValue)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/LongSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/LongSetting.kt
index c526fc4cfa..e3efd516c0 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/LongSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/LongSetting.kt
@@ -5,21 +5,21 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
-enum class LongSetting(
-    override val key: String,
-    override val category: Settings.Category
-) : AbstractLongSetting {
-    CUSTOM_RTC("custom_rtc", Settings.Category.System);
+enum class LongSetting(override val key: String) : AbstractLongSetting {
+    CUSTOM_RTC("custom_rtc");
 
-    override val long: Long
-        get() = NativeConfig.getLong(key, false)
+    override fun getLong(needsGlobal: Boolean): Long = NativeConfig.getLong(key, needsGlobal)
 
-    override fun setLong(value: Long) = NativeConfig.setLong(key, value)
+    override fun setLong(value: Long) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setLong(key, value)
+    }
 
-    override val defaultValue: Long by lazy { NativeConfig.getLong(key, true) }
+    override val defaultValue: Long by lazy { NativeConfig.getDefaultToString(key).toLong() }
 
-    override val valueAsString: String
-        get() = long.toString()
+    override fun getValueAsString(needsGlobal: Boolean): String = getLong(needsGlobal).toString()
 
     override fun reset() = NativeConfig.setLong(key, defaultValue)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
index e3cd661859..9551fc05e4 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
@@ -6,62 +6,11 @@ package org.yuzu.yuzu_emu.features.settings.model
 import org.yuzu.yuzu_emu.R
 
 object Settings {
-    enum class Category {
-        Android,
-        Audio,
-        Core,
-        Cpu,
-        CpuDebug,
-        CpuUnsafe,
-        Renderer,
-        RendererAdvanced,
-        RendererDebug,
-        System,
-        SystemAudio,
-        DataStorage,
-        Debugging,
-        DebuggingGraphics,
-        Miscellaneous,
-        Network,
-        WebService,
-        AddOns,
-        Controls,
-        Ui,
-        UiGeneral,
-        UiLayout,
-        UiGameList,
-        Screenshots,
-        Shortcuts,
-        Multiplayer,
-        Services,
-        Paths,
-        MaxEnum
-    }
-
-    val settingsList = listOf<AbstractSetting>(
-        *BooleanSetting.values(),
-        *ByteSetting.values(),
-        *ShortSetting.values(),
-        *IntSetting.values(),
-        *FloatSetting.values(),
-        *LongSetting.values(),
-        *StringSetting.values()
-    )
-
-    const val SECTION_GENERAL = "General"
-    const val SECTION_SYSTEM = "System"
-    const val SECTION_RENDERER = "Renderer"
-    const val SECTION_AUDIO = "Audio"
-    const val SECTION_CPU = "Cpu"
-    const val SECTION_THEME = "Theme"
-    const val SECTION_DEBUG = "Debug"
-
     enum class MenuTag(val titleId: Int) {
         SECTION_ROOT(R.string.advanced_settings),
         SECTION_SYSTEM(R.string.preferences_system),
         SECTION_RENDERER(R.string.preferences_graphics),
         SECTION_AUDIO(R.string.preferences_audio),
-        SECTION_CPU(R.string.cpu),
         SECTION_THEME(R.string.preferences_theme),
         SECTION_DEBUG(R.string.preferences_debug);
     }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt
index c9a0c664cb..16eb4ffdd5 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt
@@ -5,21 +5,21 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
-enum class ShortSetting(
-    override val key: String,
-    override val category: Settings.Category
-) : AbstractShortSetting {
-    RENDERER_SPEED_LIMIT("speed_limit", Settings.Category.Core);
+enum class ShortSetting(override val key: String) : AbstractShortSetting {
+    RENDERER_SPEED_LIMIT("speed_limit");
 
-    override val short: Short
-        get() = NativeConfig.getShort(key, false)
+    override fun getShort(needsGlobal: Boolean): Short = NativeConfig.getShort(key, needsGlobal)
 
-    override fun setShort(value: Short) = NativeConfig.setShort(key, value)
+    override fun setShort(value: Short) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setShort(key, value)
+    }
 
-    override val defaultValue: Short by lazy { NativeConfig.getShort(key, true) }
+    override val defaultValue: Short by lazy { NativeConfig.getDefaultToString(key).toShort() }
 
-    override val valueAsString: String
-        get() = short.toString()
+    override fun getValueAsString(needsGlobal: Boolean): String = getShort(needsGlobal).toString()
 
     override fun reset() = NativeConfig.setShort(key, defaultValue)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
index 9bb3e66d4f..a0d8cfedea 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
@@ -5,22 +5,21 @@ package org.yuzu.yuzu_emu.features.settings.model
 
 import org.yuzu.yuzu_emu.utils.NativeConfig
 
-enum class StringSetting(
-    override val key: String,
-    override val category: Settings.Category
-) : AbstractStringSetting {
-    // No string settings currently exist
-    EMPTY_SETTING("", Settings.Category.UiGeneral);
+enum class StringSetting(override val key: String) : AbstractStringSetting {
+    DRIVER_PATH("driver_path");
 
-    override val string: String
-        get() = NativeConfig.getString(key, false)
+    override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)
 
-    override fun setString(value: String) = NativeConfig.setString(key, value)
+    override fun setString(value: String) {
+        if (NativeConfig.isPerGameConfigLoaded()) {
+            global = false
+        }
+        NativeConfig.setString(key, value)
+    }
 
-    override val defaultValue: String by lazy { NativeConfig.getString(key, true) }
+    override val defaultValue: String by lazy { NativeConfig.getDefaultToString(key) }
 
-    override val valueAsString: String
-        get() = string
+    override fun getValueAsString(needsGlobal: Boolean): String = getString(needsGlobal)
 
     override fun reset() = NativeConfig.setString(key, defaultValue)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt
index 8bc1641978..1d81f5f2b4 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt
@@ -12,7 +12,6 @@ class DateTimeSetting(
 ) : SettingsItem(longSetting, titleId, descriptionId) {
     override val type = TYPE_DATETIME_SETTING
 
-    var value: Long
-        get() = longSetting.long
-        set(value) = (setting as AbstractLongSetting).setLong(value)
+    fun getValue(needsGlobal: Boolean = false): Long = longSetting.getLong(needsGlobal)
+    fun setValue(value: Long) = (setting as AbstractLongSetting).setLong(value)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
index e198b18a02..3845272946 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
@@ -11,7 +11,6 @@ import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
 import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
 import org.yuzu.yuzu_emu.features.settings.model.IntSetting
 import org.yuzu.yuzu_emu.features.settings.model.LongSetting
-import org.yuzu.yuzu_emu.features.settings.model.Settings
 import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
 
 /**
@@ -48,8 +47,8 @@ abstract class SettingsItem(
 
         val emptySetting = object : AbstractSetting {
             override val key: String = ""
-            override val category: Settings.Category = Settings.Category.Ui
             override val defaultValue: Any = false
+            override fun getValueAsString(needsGlobal: Boolean): String = ""
             override fun reset() {}
         }
 
@@ -270,9 +269,9 @@ abstract class SettingsItem(
             )
 
             val fastmem = object : AbstractBooleanSetting {
-                override val boolean: Boolean
-                    get() =
-                        BooleanSetting.FASTMEM.boolean && BooleanSetting.FASTMEM_EXCLUSIVES.boolean
+                override fun getBoolean(needsGlobal: Boolean): Boolean =
+                    BooleanSetting.FASTMEM.getBoolean() &&
+                        BooleanSetting.FASTMEM_EXCLUSIVES.getBoolean()
 
                 override fun setBoolean(value: Boolean) {
                     BooleanSetting.FASTMEM.setBoolean(value)
@@ -280,9 +279,22 @@ abstract class SettingsItem(
                 }
 
                 override val key: String = FASTMEM_COMBINED
-                override val category = Settings.Category.Cpu
                 override val isRuntimeModifiable: Boolean = false
                 override val defaultValue: Boolean = true
+                override val isSwitchable: Boolean = true
+                override var global: Boolean
+                    get() {
+                        return BooleanSetting.FASTMEM.global &&
+                            BooleanSetting.FASTMEM_EXCLUSIVES.global
+                    }
+                    set(value) {
+                        BooleanSetting.FASTMEM.global = value
+                        BooleanSetting.FASTMEM_EXCLUSIVES.global = value
+                    }
+
+                override fun getValueAsString(needsGlobal: Boolean): String =
+                    getBoolean().toString()
+
                 override fun reset() = setBoolean(defaultValue)
             }
             put(SwitchSetting(fastmem, R.string.fastmem, 0))
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt
index 705527a733..97a5a9e596 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt
@@ -15,16 +15,11 @@ class SingleChoiceSetting(
 ) : SettingsItem(setting, titleId, descriptionId) {
     override val type = TYPE_SINGLE_CHOICE
 
-    var selectedValue: Int
-        get() {
-            return when (setting) {
-                is AbstractIntSetting -> setting.int
-                else -> -1
-            }
-        }
-        set(value) {
-            when (setting) {
-                is AbstractIntSetting -> setting.setInt(value)
-            }
+    fun getSelectedValue(needsGlobal: Boolean = false) =
+        when (setting) {
+            is AbstractIntSetting -> setting.getInt(needsGlobal)
+            else -> -1
         }
+
+    fun setSelectedValue(value: Int) = (setting as AbstractIntSetting).setInt(value)
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt
index c3b5df02c9..b9b709bf7b 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt
@@ -20,22 +20,20 @@ class SliderSetting(
 ) : SettingsItem(setting, titleId, descriptionId) {
     override val type = TYPE_SLIDER
 
-    var selectedValue: Int
-        get() {
-            return when (setting) {
-                is AbstractByteSetting -> setting.byte.toInt()
-                is AbstractShortSetting -> setting.short.toInt()
-                is AbstractIntSetting -> setting.int
-                is AbstractFloatSetting -> setting.float.roundToInt()
-                else -> -1
-            }
+    fun getSelectedValue(needsGlobal: Boolean = false) =
+        when (setting) {
+            is AbstractByteSetting -> setting.getByte(needsGlobal).toInt()
+            is AbstractShortSetting -> setting.getShort(needsGlobal).toInt()
+            is AbstractIntSetting -> setting.getInt(needsGlobal)
+            is AbstractFloatSetting -> setting.getFloat(needsGlobal).roundToInt()
+            else -> -1
         }
-        set(value) {
-            when (setting) {
-                is AbstractByteSetting -> setting.setByte(value.toByte())
-                is AbstractShortSetting -> setting.setShort(value.toShort())
-                is AbstractIntSetting -> setting.setInt(value)
-                is AbstractFloatSetting -> setting.setFloat(value.toFloat())
-            }
+
+    fun setSelectedValue(value: Int) =
+        when (setting) {
+            is AbstractByteSetting -> setting.setByte(value.toByte())
+            is AbstractShortSetting -> setting.setShort(value.toShort())
+            is AbstractFloatSetting -> setting.setFloat(value.toFloat())
+            else -> (setting as AbstractIntSetting).setInt(value)
         }
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt
index 871dab4f3b..ba7920f50b 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt
@@ -17,14 +17,13 @@ class StringSingleChoiceSetting(
     fun getValueAt(index: Int): String =
         if (index >= 0 && index < values.size) values[index] else ""
 
-    var selectedValue: String
-        get() = stringSetting.string
-        set(value) = stringSetting.setString(value)
+    fun getSelectedValue(needsGlobal: Boolean = false) = stringSetting.getString(needsGlobal)
+    fun setSelectedValue(value: String) = stringSetting.setString(value)
 
     val selectValueIndex: Int
         get() {
             for (i in values.indices) {
-                if (values[i] == selectedValue) {
+                if (values[i] == getSelectedValue()) {
                     return i
                 }
             }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt
index 416967e645..44d47dd69d 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt
@@ -14,18 +14,18 @@ class SwitchSetting(
 ) : SettingsItem(setting, titleId, descriptionId) {
     override val type = TYPE_SWITCH
 
-    var checked: Boolean
-        get() {
-            return when (setting) {
-                is AbstractIntSetting -> setting.int == 1
-                is AbstractBooleanSetting -> setting.boolean
-                else -> false
-            }
+    fun getIsChecked(needsGlobal: Boolean = false): Boolean {
+        return when (setting) {
+            is AbstractIntSetting -> setting.getInt(needsGlobal) == 1
+            is AbstractBooleanSetting -> setting.getBoolean(needsGlobal)
+            else -> false
         }
-        set(value) {
-            when (setting) {
-                is AbstractIntSetting -> setting.setInt(if (value) 1 else 0)
-                is AbstractBooleanSetting -> setting.setBoolean(value)
-            }
+    }
+
+    fun setChecked(value: Boolean) {
+        when (setting) {
+            is AbstractIntSetting -> setting.setInt(if (value) 1 else 0)
+            is AbstractBooleanSetting -> setting.setBoolean(value)
         }
+    }
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
index af2c1e5820..3f23c064e2 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
@@ -102,8 +102,9 @@ class SettingsAdapter(
         return currentList[position].type
     }
 
-    fun onBooleanClick(item: SwitchSetting, checked: Boolean) {
-        item.checked = checked
+    fun onBooleanClick(item: SwitchSetting, checked: Boolean, position: Int) {
+        item.setChecked(checked)
+        notifyItemChanged(position)
         settingsViewModel.setShouldReloadSettingsList(true)
     }
 
@@ -126,7 +127,7 @@ class SettingsAdapter(
     }
 
     fun onDateTimeClick(item: DateTimeSetting, position: Int) {
-        val storedTime = item.value * 1000
+        val storedTime = item.getValue() * 1000
 
         // Helper to extract hour and minute from epoch time
         val calendar: Calendar = Calendar.getInstance()
@@ -159,9 +160,9 @@ class SettingsAdapter(
             var epochTime: Long = datePicker.selection!! / 1000
             epochTime += timePicker.hour.toLong() * 60 * 60
             epochTime += timePicker.minute.toLong() * 60
-            if (item.value != epochTime) {
+            if (item.getValue() != epochTime) {
                 notifyItemChanged(position)
-                item.value = epochTime
+                item.setValue(epochTime)
             }
         }
         datePicker.show(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
index 7425728c60..12a389b37a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -36,7 +36,14 @@ class SettingsFragmentPresenter(
         val item = SettingsItem.settingsItems[key]!!
         val pairedSettingKey = item.setting.pairedSettingKey
         if (pairedSettingKey.isNotEmpty()) {
-            val pairedSettingValue = NativeConfig.getBoolean(pairedSettingKey, false)
+            val pairedSettingValue = NativeConfig.getBoolean(
+                pairedSettingKey,
+                if (NativeLibrary.isRunning() && !NativeConfig.isPerGameConfigLoaded()) {
+                    !NativeConfig.usingGlobal(pairedSettingKey)
+                } else {
+                    NativeConfig.usingGlobal(pairedSettingKey)
+                }
+            )
             if (!pairedSettingValue) return
         }
         add(item)
@@ -153,8 +160,8 @@ class SettingsFragmentPresenter(
     private fun addThemeSettings(sl: ArrayList<SettingsItem>) {
         sl.apply {
             val theme: AbstractIntSetting = object : AbstractIntSetting {
-                override val int: Int
-                    get() = preferences.getInt(Settings.PREF_THEME, 0)
+                override fun getInt(needsGlobal: Boolean): Int =
+                    preferences.getInt(Settings.PREF_THEME, 0)
 
                 override fun setInt(value: Int) {
                     preferences.edit()
@@ -164,8 +171,8 @@ class SettingsFragmentPresenter(
                 }
 
                 override val key: String = Settings.PREF_THEME
-                override val category = Settings.Category.UiGeneral
                 override val isRuntimeModifiable: Boolean = false
+                override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
                 override val defaultValue: Int = 0
                 override fun reset() {
                     preferences.edit()
@@ -197,8 +204,8 @@ class SettingsFragmentPresenter(
             }
 
             val themeMode: AbstractIntSetting = object : AbstractIntSetting {
-                override val int: Int
-                    get() = preferences.getInt(Settings.PREF_THEME_MODE, -1)
+                override fun getInt(needsGlobal: Boolean): Int =
+                    preferences.getInt(Settings.PREF_THEME_MODE, -1)
 
                 override fun setInt(value: Int) {
                     preferences.edit()
@@ -208,8 +215,8 @@ class SettingsFragmentPresenter(
                 }
 
                 override val key: String = Settings.PREF_THEME_MODE
-                override val category = Settings.Category.UiGeneral
                 override val isRuntimeModifiable: Boolean = false
+                override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
                 override val defaultValue: Int = -1
                 override fun reset() {
                     preferences.edit()
@@ -230,8 +237,8 @@ class SettingsFragmentPresenter(
             )
 
             val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting {
-                override val boolean: Boolean
-                    get() = preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false)
+                override fun getBoolean(needsGlobal: Boolean): Boolean =
+                    preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false)
 
                 override fun setBoolean(value: Boolean) {
                     preferences.edit()
@@ -241,8 +248,10 @@ class SettingsFragmentPresenter(
                 }
 
                 override val key: String = Settings.PREF_BLACK_BACKGROUNDS
-                override val category = Settings.Category.UiGeneral
                 override val isRuntimeModifiable: Boolean = false
+                override fun getValueAsString(needsGlobal: Boolean): String =
+                    getBoolean().toString()
+
                 override val defaultValue: Boolean = false
                 override fun reset() {
                     preferences.edit()
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
index 525f013f8b..4e159a7997 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
@@ -29,7 +29,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
         }
 
         binding.textSettingValue.visibility = View.VISIBLE
-        val epochTime = setting.value
+        val epochTime = setting.getValue()
         val instant = Instant.ofEpochMilli(epochTime * 1000)
         val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"))
         val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
index 80d1b22c1a..28c4d17775 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
@@ -29,14 +29,14 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
             val resMgr = binding.textSettingValue.context.resources
             val values = resMgr.getIntArray(item.valuesId)
             for (i in values.indices) {
-                if (values[i] == item.selectedValue) {
+                if (values[i] == item.getSelectedValue()) {
                     binding.textSettingValue.text = resMgr.getStringArray(item.choicesId)[i]
                     break
                 }
             }
         } else if (item is StringSingleChoiceSetting) {
             for (i in item.values.indices) {
-                if (item.values[i] == item.selectedValue) {
+                if (item.values[i] == item.getSelectedValue()) {
                     binding.textSettingValue.text = item.choices[i]
                     break
                 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
index b83c901006..67432f88ef 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
@@ -26,7 +26,7 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
         binding.textSettingValue.visibility = View.VISIBLE
         binding.textSettingValue.text = String.format(
             binding.textSettingValue.context.getString(R.string.value_with_units),
-            setting.selectedValue,
+            setting.getSelectedValue(),
             setting.units
         )
 
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
index 57fdeaa208..98ed888cb5 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
@@ -27,7 +27,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
         }
 
         binding.switchWidget.setOnCheckedChangeListener(null)
-        binding.switchWidget.isChecked = setting.checked
+        binding.switchWidget.isChecked = setting.getIsChecked(setting.needsRuntimeGlobal)
         binding.switchWidget.setOnCheckedChangeListener { _: CompoundButton, _: Boolean ->
             adapter.onBooleanClick(item, binding.switchWidget.isChecked)
         }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index 734c1d5ca7..b09df7db34 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -435,7 +435,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
     @SuppressLint("SourceLockedOrientationActivity")
     private fun updateOrientation() {
         emulationActivity?.let {
-            it.requestedOrientation = when (IntSetting.RENDERER_SCREEN_LAYOUT.int) {
+            it.requestedOrientation = when (IntSetting.RENDERER_SCREEN_LAYOUT.getInt()) {
                 Settings.LayoutOption_MobileLandscape ->
                     ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
                 Settings.LayoutOption_MobilePortrait ->
@@ -617,7 +617,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
     @SuppressLint("SourceLockedOrientationActivity")
     private fun startConfiguringControls() {
         // Lock the current orientation to prevent editing inconsistencies
-        if (IntSetting.RENDERER_SCREEN_LAYOUT.int == Settings.LayoutOption_Unspecified) {
+        if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == Settings.LayoutOption_Unspecified) {
             emulationActivity?.let {
                 it.requestedOrientation =
                     if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
@@ -635,7 +635,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
         binding.doneControlConfig.visibility = View.GONE
         binding.surfaceInputOverlay.setIsInEditMode(false)
         // Unlock the orientation if it was locked for editing
-        if (IntSetting.RENDERER_SCREEN_LAYOUT.int == Settings.LayoutOption_Unspecified) {
+        if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == Settings.LayoutOption_Unspecified) {
             emulationActivity?.let {
                 it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
             }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt
index b88d2c0381..60e029f34f 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsDialogFragment.kt
@@ -70,7 +70,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
                 sliderBinding = DialogSliderBinding.inflate(layoutInflater)
                 val item = settingsViewModel.clickedItem as SliderSetting
 
-                settingsViewModel.setSliderTextValue(item.selectedValue.toFloat(), item.units)
+                settingsViewModel.setSliderTextValue(item.getSelectedValue().toFloat(), item.units)
                 sliderBinding.slider.apply {
                     valueFrom = item.min.toFloat()
                     valueTo = item.max.toFloat()
@@ -136,18 +136,18 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
             is SingleChoiceSetting -> {
                 val scSetting = settingsViewModel.clickedItem as SingleChoiceSetting
                 val value = getValueForSingleChoiceSelection(scSetting, which)
-                scSetting.selectedValue = value
+                scSetting.setSelectedValue(value)
             }
 
             is StringSingleChoiceSetting -> {
                 val scSetting = settingsViewModel.clickedItem as StringSingleChoiceSetting
                 val value = scSetting.getValueAt(which)
-                scSetting.selectedValue = value
+                scSetting.setSelectedValue(value)
             }
 
             is SliderSetting -> {
                 val sliderSetting = settingsViewModel.clickedItem as SliderSetting
-                sliderSetting.selectedValue = settingsViewModel.sliderProgress.value
+                sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
             }
         }
         closeDialog()
@@ -171,7 +171,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
     }
 
     private fun getSelectionForSingleChoiceValue(item: SingleChoiceSetting): Int {
-        val value = item.selectedValue
+        val value = item.getSelectedValue()
         val valuesId = item.valuesId
         if (valuesId > 0) {
             val valuesArray = requireContext().resources.getIntArray(valuesId)
@@ -211,7 +211,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
                     throw IllegalArgumentException("[SettingsDialogFragment] Incompatible type!")
 
                 SettingsItem.TYPE_SLIDER -> settingsViewModel.setSliderProgress(
-                    (clickedItem as SliderSetting).selectedValue.toFloat()
+                    (clickedItem as SliderSetting).getSelectedValue().toFloat()
                 )
             }
             settingsViewModel.clickedItem = clickedItem
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt
index f4e1bb13fc..4c7316ba39 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt
@@ -31,32 +31,63 @@ object NativeConfig {
     external fun saveSettings()
 
     external fun getBoolean(key: String, getDefault: Boolean): Boolean
+
+    @Synchronized
+    external fun getBoolean(key: String, needsGlobal: Boolean): Boolean
+
+    @Synchronized
     external fun setBoolean(key: String, value: Boolean)
 
-    external fun getByte(key: String, getDefault: Boolean): Byte
+    @Synchronized
+    external fun getByte(key: String, needsGlobal: Boolean): Byte
+
+    @Synchronized
     external fun setByte(key: String, value: Byte)
 
-    external fun getShort(key: String, getDefault: Boolean): Short
+    @Synchronized
+    external fun getShort(key: String, needsGlobal: Boolean): Short
+
+    @Synchronized
     external fun setShort(key: String, value: Short)
 
-    external fun getInt(key: String, getDefault: Boolean): Int
+    @Synchronized
+    external fun getInt(key: String, needsGlobal: Boolean): Int
+
+    @Synchronized
     external fun setInt(key: String, value: Int)
 
-    external fun getFloat(key: String, getDefault: Boolean): Float
+    @Synchronized
+    external fun getFloat(key: String, needsGlobal: Boolean): Float
+
+    @Synchronized
     external fun setFloat(key: String, value: Float)
 
-    external fun getLong(key: String, getDefault: Boolean): Long
+    @Synchronized
+    external fun getLong(key: String, needsGlobal: Boolean): Long
+
+    @Synchronized
     external fun setLong(key: String, value: Long)
 
-    external fun getString(key: String, getDefault: Boolean): String
+    @Synchronized
+    external fun getString(key: String, needsGlobal: Boolean): String
+
+    @Synchronized
     external fun setString(key: String, value: String)
 
     external fun getIsRuntimeModifiable(key: String): Boolean
 
-    external fun getConfigHeader(category: Int): String
-
     external fun getPairedSettingKey(key: String): String
 
+    external fun getIsSwitchable(key: String): Boolean
+
+    @Synchronized
+    external fun usingGlobal(key: String): Boolean
+
+    @Synchronized
+    external fun setGlobal(key: String, global: Boolean)
+
+    external fun getDefaultToString(key: String): String
+
     /**
      * Gets every [GameDir] in AndroidSettings::values.game_dirs
      */
diff --git a/src/android/app/src/main/jni/native_config.cpp b/src/android/app/src/main/jni/native_config.cpp
index 763b2164c5..9439d11e14 100644
--- a/src/android/app/src/main/jni/native_config.cpp
+++ b/src/android/app/src/main/jni/native_config.cpp
@@ -49,18 +49,12 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveSettings(JNIEnv* env, jobjec
 }
 
 jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getBoolean(JNIEnv* env, jobject obj,
-                                                               jstring jkey, jboolean getDefault) {
+                                                               jstring jkey, jboolean needGlobal) {
     auto setting = getSetting<bool>(env, jkey);
     if (setting == nullptr) {
         return false;
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return setting->GetDefault();
-    }
-
-    return setting->GetValue();
+    return setting->GetValue(static_cast<bool>(needGlobal));
 }
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setBoolean(JNIEnv* env, jobject obj, jstring jkey,
@@ -69,23 +63,16 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setBoolean(JNIEnv* env, jobject
     if (setting == nullptr) {
         return;
     }
-    setting->SetGlobal(true);
     setting->SetValue(static_cast<bool>(value));
 }
 
 jbyte Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getByte(JNIEnv* env, jobject obj, jstring jkey,
-                                                         jboolean getDefault) {
+                                                         jboolean needGlobal) {
     auto setting = getSetting<u8>(env, jkey);
     if (setting == nullptr) {
         return -1;
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return setting->GetDefault();
-    }
-
-    return setting->GetValue();
+    return setting->GetValue(static_cast<bool>(needGlobal));
 }
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setByte(JNIEnv* env, jobject obj, jstring jkey,
@@ -94,23 +81,16 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setByte(JNIEnv* env, jobject obj
     if (setting == nullptr) {
         return;
     }
-    setting->SetGlobal(true);
     setting->SetValue(value);
 }
 
 jshort Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getShort(JNIEnv* env, jobject obj, jstring jkey,
-                                                           jboolean getDefault) {
+                                                           jboolean needGlobal) {
     auto setting = getSetting<u16>(env, jkey);
     if (setting == nullptr) {
         return -1;
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return setting->GetDefault();
-    }
-
-    return setting->GetValue();
+    return setting->GetValue(static_cast<bool>(needGlobal));
 }
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setShort(JNIEnv* env, jobject obj, jstring jkey,
@@ -119,23 +99,16 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setShort(JNIEnv* env, jobject ob
     if (setting == nullptr) {
         return;
     }
-    setting->SetGlobal(true);
     setting->SetValue(value);
 }
 
 jint Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getInt(JNIEnv* env, jobject obj, jstring jkey,
-                                                       jboolean getDefault) {
+                                                       jboolean needGlobal) {
     auto setting = getSetting<int>(env, jkey);
     if (setting == nullptr) {
         return -1;
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return setting->GetDefault();
-    }
-
-    return setting->GetValue();
+    return setting->GetValue(needGlobal);
 }
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setInt(JNIEnv* env, jobject obj, jstring jkey,
@@ -144,23 +117,16 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setInt(JNIEnv* env, jobject obj,
     if (setting == nullptr) {
         return;
     }
-    setting->SetGlobal(true);
     setting->SetValue(value);
 }
 
 jfloat Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getFloat(JNIEnv* env, jobject obj, jstring jkey,
-                                                           jboolean getDefault) {
+                                                           jboolean needGlobal) {
     auto setting = getSetting<float>(env, jkey);
     if (setting == nullptr) {
         return -1;
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return setting->GetDefault();
-    }
-
-    return setting->GetValue();
+    return setting->GetValue(static_cast<bool>(needGlobal));
 }
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setFloat(JNIEnv* env, jobject obj, jstring jkey,
@@ -169,23 +135,16 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setFloat(JNIEnv* env, jobject ob
     if (setting == nullptr) {
         return;
     }
-    setting->SetGlobal(true);
     setting->SetValue(value);
 }
 
 jlong Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getLong(JNIEnv* env, jobject obj, jstring jkey,
-                                                         jboolean getDefault) {
-    auto setting = getSetting<long>(env, jkey);
+                                                         jboolean needGlobal) {
+    auto setting = getSetting<s64>(env, jkey);
     if (setting == nullptr) {
         return -1;
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return setting->GetDefault();
-    }
-
-    return setting->GetValue();
+    return setting->GetValue(static_cast<bool>(needGlobal));
 }
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setLong(JNIEnv* env, jobject obj, jstring jkey,
@@ -194,23 +153,16 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setLong(JNIEnv* env, jobject obj
     if (setting == nullptr) {
         return;
     }
-    setting->SetGlobal(true);
     setting->SetValue(value);
 }
 
 jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getString(JNIEnv* env, jobject obj, jstring jkey,
-                                                             jboolean getDefault) {
+                                                             jboolean needGlobal) {
     auto setting = getSetting<std::string>(env, jkey);
     if (setting == nullptr) {
         return ToJString(env, "");
     }
-    setting->SetGlobal(true);
-
-    if (static_cast<bool>(getDefault)) {
-        return ToJString(env, setting->GetDefault());
-    }
-
-    return ToJString(env, setting->GetValue());
+    return ToJString(env, setting->GetValue(static_cast<bool>(needGlobal)));
 }
 
 void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject obj, jstring jkey,
@@ -220,27 +172,18 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject o
         return;
     }
 
-    setting->SetGlobal(true);
     setting->SetValue(GetJString(env, value));
 }
 
 jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsRuntimeModifiable(JNIEnv* env, jobject obj,
                                                                            jstring jkey) {
-    auto key = GetJString(env, jkey);
-    auto setting = Settings::values.linkage.by_key[key];
-    if (setting != 0) {
+    auto setting = getSetting<std::string>(env, jkey);
+    if (setting != nullptr) {
         return setting->RuntimeModfiable();
     }
-    LOG_ERROR(Frontend, "[Android Native] Could not find setting - {}", key);
     return true;
 }
 
-jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getConfigHeader(JNIEnv* env, jobject obj,
-                                                                   jint jcategory) {
-    auto category = static_cast<Settings::Category>(jcategory);
-    return ToJString(env, Settings::TranslateCategory(category));
-}
-
 jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getPairedSettingKey(JNIEnv* env, jobject obj,
                                                                        jstring jkey) {
     auto setting = getSetting<std::string>(env, jkey);
@@ -254,6 +197,41 @@ jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getPairedSettingKey(JNIEnv* e
     return ToJString(env, setting->PairedSetting()->GetLabel());
 }
 
+jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsSwitchable(JNIEnv* env, jobject obj,
+                                                                    jstring jkey) {
+    auto setting = getSetting<std::string>(env, jkey);
+    if (setting != nullptr) {
+        return setting->Switchable();
+    }
+    return false;
+}
+
+jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_usingGlobal(JNIEnv* env, jobject obj,
+                                                                jstring jkey) {
+    auto setting = getSetting<std::string>(env, jkey);
+    if (setting != nullptr) {
+        return setting->UsingGlobal();
+    }
+    return true;
+}
+
+void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setGlobal(JNIEnv* env, jobject obj, jstring jkey,
+                                                          jboolean global) {
+    auto setting = getSetting<std::string>(env, jkey);
+    if (setting != nullptr) {
+        setting->SetGlobal(static_cast<bool>(global));
+    }
+}
+
+jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDefaultToString(JNIEnv* env, jobject obj,
+                                                                      jstring jkey) {
+    auto setting = getSetting<std::string>(env, jkey);
+    if (setting != nullptr) {
+        return ToJString(env, setting->DefaultToString());
+    }
+    return ToJString(env, "");
+}
+
 jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getGameDirs(JNIEnv* env, jobject obj) {
     jclass gameDirClass = IDCache::GetGameDirClass();
     jmethodID gameDirConstructor = IDCache::GetGameDirConstructor();
diff --git a/src/common/settings_setting.h b/src/common/settings_setting.h
index 3175ab07d1..0b18ca5ecc 100644
--- a/src/common/settings_setting.h
+++ b/src/common/settings_setting.h
@@ -81,6 +81,9 @@ public:
     [[nodiscard]] virtual const Type& GetValue() const {
         return value;
     }
+    [[nodiscard]] virtual const Type& GetValue(bool need_global) const {
+        return value;
+    }
 
     /**
      * Sets the setting to the given value.
@@ -353,7 +356,7 @@ public:
         }
         return custom;
     }
-    [[nodiscard]] const Type& GetValue(bool need_global) const {
+    [[nodiscard]] const Type& GetValue(bool need_global) const override final {
         if (use_global || need_global) {
             return this->value;
         }