diff --git a/.codespellrc b/.codespellrc
index 01ddd23624..944194a257 100644
--- a/.codespellrc
+++ b/.codespellrc
@@ -3,4 +3,4 @@
 
 [codespell]
 skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES,./src/android/app/src/main/res
-ignore-words-list = aci,allright,ba,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,zink
+ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,zink
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0696201dfc..2da983cad8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -35,6 +35,7 @@ if (MSVC)
     # /volatile:iso       - Use strict standards-compliant volatile semantics.
     # /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates
     # /Zc:inline          - Let codegen omit inline functions in object files
+    # /Zc:preprocessor    - Enable standards-conforming preprocessor
     # /Zc:throwingNew     - Let codegen assume `operator new` (without std::nothrow) will never return null
     # /GT                 - Supports fiber safety for data allocated using static thread-local storage
     add_compile_options(
@@ -48,6 +49,7 @@ if (MSVC)
         /volatile:iso
         /Zc:externConstexpr
         /Zc:inline
+        /Zc:preprocessor
         /Zc:throwingNew
         /GT
 
diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp
index 43e8aa72a2..5e1f10f99f 100644
--- a/src/android/app/src/main/jni/config.cpp
+++ b/src/android/app/src/main/jni/config.cpp
@@ -150,15 +150,17 @@ void Config::ReadValues() {
     if (rng_seed_enabled) {
         Settings::values.rng_seed.SetValue(config->GetInteger("System", "rng_seed", 0));
     } else {
-        Settings::values.rng_seed.SetValue(std::nullopt);
+        Settings::values.rng_seed.SetValue(0);
     }
+    Settings::values.rng_seed_enabled.SetValue(rng_seed_enabled);
 
     const auto custom_rtc_enabled = config->GetBoolean("System", "custom_rtc_enabled", false);
     if (custom_rtc_enabled) {
         Settings::values.custom_rtc = config->GetInteger("System", "custom_rtc", 0);
     } else {
-        Settings::values.custom_rtc = std::nullopt;
+        Settings::values.custom_rtc = 0;
     }
+    Settings::values.custom_rtc_enabled = custom_rtc_enabled;
 
     ReadSetting("System", Settings::values.language_index);
     ReadSetting("System", Settings::values.region_index);
@@ -167,7 +169,7 @@ void Config::ReadValues() {
 
     // Core
     ReadSetting("Core", Settings::values.use_multi_core);
-    ReadSetting("Core", Settings::values.use_unsafe_extended_memory_layout);
+    ReadSetting("Core", Settings::values.memory_layout_mode);
 
     // Cpu
     ReadSetting("Cpu", Settings::values.cpu_accuracy);
@@ -222,14 +224,17 @@ void Config::ReadValues() {
     ReadSetting("Renderer", Settings::values.bg_blue);
 
     // Use GPU accuracy normal by default on Android
-    Settings::values.gpu_accuracy = static_cast<Settings::GPUAccuracy>(config->GetInteger(
-        "Renderer", "gpu_accuracy", static_cast<u32>(Settings::GPUAccuracy::Normal)));
+    Settings::values.gpu_accuracy = static_cast<Settings::GpuAccuracy>(config->GetInteger(
+        "Renderer", "gpu_accuracy", static_cast<u32>(Settings::GpuAccuracy::Normal)));
 
     // Use GPU default anisotropic filtering on Android
-    Settings::values.max_anisotropy = config->GetInteger("Renderer", "max_anisotropy", 1);
+    Settings::values.max_anisotropy =
+        static_cast<Settings::AnisotropyMode>(config->GetInteger("Renderer", "max_anisotropy", 1));
 
     // Disable ASTC compute by default on Android
-    Settings::values.accelerate_astc = config->GetBoolean("Renderer", "accelerate_astc", false);
+    Settings::values.accelerate_astc.SetValue(
+        config->GetBoolean("Renderer", "accelerate_astc", false) ? Settings::AstcDecodeMode::Gpu
+                                                                 : Settings::AstcDecodeMode::Cpu);
 
     // Enable asynchronous presentation by default on Android
     Settings::values.async_presentation =
diff --git a/src/audio_core/sink/sink_details.cpp b/src/audio_core/sink/sink_details.cpp
index 39ea6d91b8..027bfa517e 100644
--- a/src/audio_core/sink/sink_details.cpp
+++ b/src/audio_core/sink/sink_details.cpp
@@ -15,6 +15,7 @@
 #endif
 #include "audio_core/sink/null_sink.h"
 #include "common/logging/log.h"
+#include "common/settings_enums.h"
 
 namespace AudioCore::Sink {
 namespace {
@@ -24,7 +25,7 @@ struct SinkDetails {
     using LatencyFn = u32 (*)();
 
     /// Name for this sink.
-    std::string_view id;
+    Settings::AudioEngine id;
     /// A method to call to construct an instance of this type of sink.
     FactoryFn factory;
     /// A method to call to list available devices.
@@ -37,7 +38,7 @@ struct SinkDetails {
 constexpr SinkDetails sink_details[] = {
 #ifdef HAVE_CUBEB
     SinkDetails{
-        "cubeb",
+        Settings::AudioEngine::Cubeb,
         [](std::string_view device_id) -> std::unique_ptr<Sink> {
             return std::make_unique<CubebSink>(device_id);
         },
@@ -47,7 +48,7 @@ constexpr SinkDetails sink_details[] = {
 #endif
 #ifdef HAVE_SDL2
     SinkDetails{
-        "sdl2",
+        Settings::AudioEngine::Sdl2,
         [](std::string_view device_id) -> std::unique_ptr<Sink> {
             return std::make_unique<SDLSink>(device_id);
         },
@@ -55,46 +56,47 @@ constexpr SinkDetails sink_details[] = {
         &GetSDLLatency,
     },
 #endif
-    SinkDetails{"null",
+    SinkDetails{Settings::AudioEngine::Null,
                 [](std::string_view device_id) -> std::unique_ptr<Sink> {
                     return std::make_unique<NullSink>(device_id);
                 },
                 [](bool capture) { return std::vector<std::string>{"null"}; }, []() { return 0u; }},
 };
 
-const SinkDetails& GetOutputSinkDetails(std::string_view sink_id) {
-    const auto find_backend{[](std::string_view id) {
+const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
+    const auto find_backend{[](Settings::AudioEngine id) {
         return std::find_if(std::begin(sink_details), std::end(sink_details),
                             [&id](const auto& sink_detail) { return sink_detail.id == id; });
     }};
 
     auto iter = find_backend(sink_id);
 
-    if (sink_id == "auto") {
+    if (sink_id == Settings::AudioEngine::Auto) {
         // Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
         // causes audio issues, in that case go with SDL.
 #if defined(HAVE_CUBEB) && defined(HAVE_SDL2)
-        iter = find_backend("cubeb");
+        iter = find_backend(Settings::AudioEngine::Cubeb);
         if (iter->latency() > TargetSampleCount * 3) {
-            iter = find_backend("sdl2");
+            iter = find_backend(Settings::AudioEngine::Sdl2);
         }
 #else
         iter = std::begin(sink_details);
 #endif
-        LOG_INFO(Service_Audio, "Auto-selecting the {} backend", iter->id);
+        LOG_INFO(Service_Audio, "Auto-selecting the {} backend",
+                 Settings::CanonicalizeEnum(iter->id));
     }
 
     if (iter == std::end(sink_details)) {
-        LOG_ERROR(Audio, "Invalid sink_id {}", sink_id);
-        iter = find_backend("null");
+        LOG_ERROR(Audio, "Invalid sink_id {}", Settings::CanonicalizeEnum(sink_id));
+        iter = find_backend(Settings::AudioEngine::Null);
     }
 
     return *iter;
 }
 } // Anonymous namespace
 
-std::vector<std::string_view> GetSinkIDs() {
-    std::vector<std::string_view> sink_ids(std::size(sink_details));
+std::vector<Settings::AudioEngine> GetSinkIDs() {
+    std::vector<Settings::AudioEngine> sink_ids(std::size(sink_details));
 
     std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids),
                    [](const auto& sink) { return sink.id; });
@@ -102,11 +104,11 @@ std::vector<std::string_view> GetSinkIDs() {
     return sink_ids;
 }
 
-std::vector<std::string> GetDeviceListForSink(std::string_view sink_id, bool capture) {
+std::vector<std::string> GetDeviceListForSink(Settings::AudioEngine sink_id, bool capture) {
     return GetOutputSinkDetails(sink_id).list_devices(capture);
 }
 
-std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id) {
+std::unique_ptr<Sink> CreateSinkFromID(Settings::AudioEngine sink_id, std::string_view device_id) {
     return GetOutputSinkDetails(sink_id).factory(device_id);
 }
 
diff --git a/src/audio_core/sink/sink_details.h b/src/audio_core/sink/sink_details.h
index e75932898c..c8498842b9 100644
--- a/src/audio_core/sink/sink_details.h
+++ b/src/audio_core/sink/sink_details.h
@@ -3,9 +3,11 @@
 
 #pragma once
 
+#include <memory>
 #include <string>
 #include <string_view>
 #include <vector>
+#include "common/settings_enums.h"
 
 namespace AudioCore {
 class AudioManager;
@@ -19,7 +21,7 @@ class Sink;
  *
  * @return Vector of available sink names.
  */
-std::vector<std::string_view> GetSinkIDs();
+std::vector<Settings::AudioEngine> GetSinkIDs();
 
 /**
  * Gets the list of devices for a particular sink identified by the given ID.
@@ -28,7 +30,7 @@ std::vector<std::string_view> GetSinkIDs();
  * @param capture - Get capture (input) devices, or output devices?
  * @return Vector of device names.
  */
-std::vector<std::string> GetDeviceListForSink(std::string_view sink_id, bool capture);
+std::vector<std::string> GetDeviceListForSink(Settings::AudioEngine sink_id, bool capture);
 
 /**
  * Creates an audio sink identified by the given device ID.
@@ -37,7 +39,7 @@ std::vector<std::string> GetDeviceListForSink(std::string_view sink_id, bool cap
  * @param device_id - Name of the device to create.
  * @return Pointer to the created sink.
  */
-std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id);
+std::unique_ptr<Sink> CreateSinkFromID(Settings::AudioEngine sink_id, std::string_view device_id);
 
 } // namespace Sink
 } // namespace AudioCore
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 3adf13a3f4..bf97d9ba28 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -110,8 +110,12 @@ add_library(common STATIC
     scratch_buffer.h
     settings.cpp
     settings.h
+    settings_common.cpp
+    settings_common.h
+    settings_enums.h
     settings_input.cpp
     settings_input.h
+    settings_setting.h
     socket_types.h
     spin_lock.cpp
     spin_lock.h
@@ -193,9 +197,16 @@ if (MSVC)
     /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
     /we4800 # Implicit conversion from 'type' to bool. Possible information loss
   )
-else()
+endif()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
   target_compile_options(common PRIVATE
-    $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
+    -fsized-deallocation
+    -Werror=unreachable-code-aggressive
+  )
+  target_compile_definitions(common PRIVATE
+    # Clang 14 and earlier have errors when explicitly instantiating Settings::Setting
+    $<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,15>:CANNOT_EXPLICITLY_INSTANTIATE>
   )
 endif()
 
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 6e8e8eb36b..d4f27197c9 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -108,7 +108,7 @@ public:
 
         using namespace Common::Literals;
         // Prevent logs from exceeding a set maximum size in the event that log entries are spammed.
-        const auto write_limit = Settings::values.extended_logging ? 1_GiB : 100_MiB;
+        const auto write_limit = Settings::values.extended_logging.GetValue() ? 1_GiB : 100_MiB;
         const bool write_limit_exceeded = bytes_written > write_limit;
         if (entry.log_level >= Level::Error || write_limit_exceeded) {
             if (write_limit_exceeded) {
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index d4e55f9888..15fd2e2227 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -7,9 +7,16 @@
 #include <exception>
 #include <stdexcept>
 #endif
+#include <compare>
+#include <cstddef>
+#include <filesystem>
+#include <functional>
 #include <string_view>
+#include <type_traits>
+#include <fmt/core.h>
 
 #include "common/assert.h"
+#include "common/fs/fs_util.h"
 #include "common/fs/path_util.h"
 #include "common/logging/log.h"
 #include "common/settings.h"
@@ -17,11 +24,50 @@
 
 namespace Settings {
 
-Values values;
-static bool configuring_global = true;
+// Clang 14 and earlier have errors when explicitly instantiating these classes
+#ifndef CANNOT_EXPLICITLY_INSTANTIATE
+#define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED>
+#define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED>
 
-std::string GetTimeZoneString() {
-    const auto time_zone_index = static_cast<std::size_t>(values.time_zone_index.GetValue());
+SETTING(AudioEngine, false);
+SETTING(bool, false);
+SETTING(int, false);
+SETTING(std::string, false);
+SETTING(u16, false);
+SWITCHABLE(AnisotropyMode, true);
+SWITCHABLE(AntiAliasing, false);
+SWITCHABLE(AspectRatio, true);
+SWITCHABLE(AstcDecodeMode, true);
+SWITCHABLE(AstcRecompression, true);
+SWITCHABLE(AudioMode, true);
+SWITCHABLE(CpuAccuracy, true);
+SWITCHABLE(FullscreenMode, true);
+SWITCHABLE(GpuAccuracy, true);
+SWITCHABLE(Language, true);
+SWITCHABLE(NvdecEmulation, false);
+SWITCHABLE(Region, true);
+SWITCHABLE(RendererBackend, true);
+SWITCHABLE(ScalingFilter, false);
+SWITCHABLE(ShaderBackend, true);
+SWITCHABLE(TimeZone, true);
+SETTING(VSyncMode, true);
+SWITCHABLE(bool, false);
+SWITCHABLE(int, false);
+SWITCHABLE(int, true);
+SWITCHABLE(s64, false);
+SWITCHABLE(u16, true);
+SWITCHABLE(u32, false);
+SWITCHABLE(u8, false);
+SWITCHABLE(u8, true);
+
+#undef SETTING
+#undef SWITCHABLE
+#endif
+
+Values values;
+
+std::string GetTimeZoneString(TimeZone time_zone) {
+    const auto time_zone_index = static_cast<std::size_t>(time_zone);
     ASSERT(time_zone_index < Common::TimeZone::GetTimeZoneStrings().size());
 
     std::string location_name;
@@ -61,73 +107,35 @@ void LogSettings() {
     };
 
     LOG_INFO(Config, "yuzu Configuration:");
-    log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
-    log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
-    log_setting("System_DeviceName", values.device_name.GetValue());
-    log_setting("System_CurrentUser", values.current_user.GetValue());
-    log_setting("System_LanguageIndex", values.language_index.GetValue());
-    log_setting("System_RegionIndex", values.region_index.GetValue());
-    log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
-    log_setting("System_UnsafeMemoryLayout", values.use_unsafe_extended_memory_layout.GetValue());
-    log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
-    log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
-    log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue());
-    log_setting("Renderer_ScalingFilter", values.scaling_filter.GetValue());
-    log_setting("Renderer_FSRSlider", values.fsr_sharpening_slider.GetValue());
-    log_setting("Renderer_AntiAliasing", values.anti_aliasing.GetValue());
-    log_setting("Renderer_UseSpeedLimit", values.use_speed_limit.GetValue());
-    log_setting("Renderer_SpeedLimit", values.speed_limit.GetValue());
-    log_setting("Renderer_UseDiskShaderCache", values.use_disk_shader_cache.GetValue());
-    log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue());
-    log_setting("Renderer_UseAsynchronousGpuEmulation",
-                values.use_asynchronous_gpu_emulation.GetValue());
-    log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue());
-    log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue());
-    log_setting("Renderer_AsyncASTC", values.async_astc.GetValue());
-    log_setting("Renderer_AstcRecompression", values.astc_recompression.GetValue());
-    log_setting("Renderer_UseVsync", values.vsync_mode.GetValue());
-    log_setting("Renderer_UseReactiveFlushing", values.use_reactive_flushing.GetValue());
-    log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue());
-    log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
-    log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
-    log_setting("Audio_OutputEngine", values.sink_id.GetValue());
-    log_setting("Audio_OutputDevice", values.audio_output_device_id.GetValue());
-    log_setting("Audio_InputDevice", values.audio_input_device_id.GetValue());
-    log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd.GetValue());
+    for (auto& [category, settings] : values.linkage.by_category) {
+        for (const auto& setting : settings) {
+            if (setting->Id() == values.yuzu_token.Id()) {
+                // Hide the token secret, for security reasons.
+                continue;
+            }
+
+            const auto name = fmt::format(
+                "{:c}{:c} {}.{}", setting->ToString() == setting->DefaultToString() ? '-' : 'M',
+                setting->UsingGlobal() ? '-' : 'C', TranslateCategory(category),
+                setting->GetLabel());
+
+            log_setting(name, setting->Canonicalize());
+        }
+    }
     log_path("DataStorage_CacheDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir));
     log_path("DataStorage_ConfigDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir));
     log_path("DataStorage_LoadDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::LoadDir));
     log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir));
     log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
-    log_setting("Debugging_ProgramArgs", values.program_args.GetValue());
-    log_setting("Debugging_GDBStub", values.use_gdbstub.GetValue());
-    log_setting("Input_EnableMotion", values.motion_enabled.GetValue());
-    log_setting("Input_EnableVibration", values.vibration_enabled.GetValue());
-    log_setting("Input_EnableTouch", values.touchscreen.enabled);
-    log_setting("Input_EnableMouse", values.mouse_enabled.GetValue());
-    log_setting("Input_EnableKeyboard", values.keyboard_enabled.GetValue());
-    log_setting("Input_EnableRingController", values.enable_ring_controller.GetValue());
-    log_setting("Input_EnableIrSensor", values.enable_ir_sensor.GetValue());
-    log_setting("Input_EnableCustomJoycon", values.enable_joycon_driver.GetValue());
-    log_setting("Input_EnableCustomProController", values.enable_procon_driver.GetValue());
-    log_setting("Input_EnableRawInput", values.enable_raw_input.GetValue());
-}
-
-bool IsConfiguringGlobal() {
-    return configuring_global;
-}
-
-void SetConfiguringGlobal(bool is_global) {
-    configuring_global = is_global;
 }
 
 bool IsGPULevelExtreme() {
-    return values.gpu_accuracy.GetValue() == GPUAccuracy::Extreme;
+    return values.gpu_accuracy.GetValue() == GpuAccuracy::Extreme;
 }
 
 bool IsGPULevelHigh() {
-    return values.gpu_accuracy.GetValue() == GPUAccuracy::Extreme ||
-           values.gpu_accuracy.GetValue() == GPUAccuracy::High;
+    return values.gpu_accuracy.GetValue() == GpuAccuracy::Extreme ||
+           values.gpu_accuracy.GetValue() == GpuAccuracy::High;
 }
 
 bool IsFastmemEnabled() {
@@ -144,6 +152,61 @@ float Volume() {
     return values.volume.GetValue() / static_cast<f32>(values.volume.GetDefault());
 }
 
+const char* TranslateCategory(Category category) {
+    switch (category) {
+    case Category::Audio:
+        return "Audio";
+    case Category::Core:
+        return "Core";
+    case Category::Cpu:
+    case Category::CpuDebug:
+    case Category::CpuUnsafe:
+        return "Cpu";
+    case Category::Renderer:
+    case Category::RendererAdvanced:
+    case Category::RendererDebug:
+        return "Renderer";
+    case Category::System:
+    case Category::SystemAudio:
+        return "System";
+    case Category::DataStorage:
+        return "Data Storage";
+    case Category::Debugging:
+    case Category::DebuggingGraphics:
+        return "Debugging";
+    case Category::Miscellaneous:
+        return "Miscellaneous";
+    case Category::Network:
+        return "Network";
+    case Category::WebService:
+        return "WebService";
+    case Category::AddOns:
+        return "DisabledAddOns";
+    case Category::Controls:
+        return "Controls";
+    case Category::Ui:
+    case Category::UiGeneral:
+        return "UI";
+    case Category::UiLayout:
+        return "UiLayout";
+    case Category::UiGameList:
+        return "UiGameList";
+    case Category::Screenshots:
+        return "Screenshots";
+    case Category::Shortcuts:
+        return "Shortcuts";
+    case Category::Multiplayer:
+        return "Multiplayer";
+    case Category::Services:
+        return "Services";
+    case Category::Paths:
+        return "Paths";
+    case Category::MaxEnum:
+        break;
+    }
+    return "Miscellaneous";
+}
+
 void UpdateRescalingInfo() {
     const auto setup = values.resolution_setup.GetValue();
     auto& info = values.resolution_info;
@@ -212,66 +275,19 @@ void RestoreGlobalState(bool is_powered_on) {
         return;
     }
 
-    // Audio
-    values.volume.SetGlobal(true);
+    for (const auto& reset : values.linkage.restore_functions) {
+        reset();
+    }
+}
 
-    // Core
-    values.use_multi_core.SetGlobal(true);
-    values.use_unsafe_extended_memory_layout.SetGlobal(true);
+static bool configuring_global = true;
 
-    // CPU
-    values.cpu_accuracy.SetGlobal(true);
-    values.cpuopt_unsafe_unfuse_fma.SetGlobal(true);
-    values.cpuopt_unsafe_reduce_fp_error.SetGlobal(true);
-    values.cpuopt_unsafe_ignore_standard_fpcr.SetGlobal(true);
-    values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true);
-    values.cpuopt_unsafe_fastmem_check.SetGlobal(true);
-    values.cpuopt_unsafe_ignore_global_monitor.SetGlobal(true);
+bool IsConfiguringGlobal() {
+    return configuring_global;
+}
 
-    // Renderer
-    values.fsr_sharpening_slider.SetGlobal(true);
-    values.renderer_backend.SetGlobal(true);
-    values.async_presentation.SetGlobal(true);
-    values.renderer_force_max_clock.SetGlobal(true);
-    values.vulkan_device.SetGlobal(true);
-    values.fullscreen_mode.SetGlobal(true);
-    values.aspect_ratio.SetGlobal(true);
-    values.resolution_setup.SetGlobal(true);
-    values.scaling_filter.SetGlobal(true);
-    values.anti_aliasing.SetGlobal(true);
-    values.max_anisotropy.SetGlobal(true);
-    values.use_speed_limit.SetGlobal(true);
-    values.speed_limit.SetGlobal(true);
-    values.use_disk_shader_cache.SetGlobal(true);
-    values.gpu_accuracy.SetGlobal(true);
-    values.use_asynchronous_gpu_emulation.SetGlobal(true);
-    values.nvdec_emulation.SetGlobal(true);
-    values.accelerate_astc.SetGlobal(true);
-    values.async_astc.SetGlobal(true);
-    values.astc_recompression.SetGlobal(true);
-    values.use_reactive_flushing.SetGlobal(true);
-    values.shader_backend.SetGlobal(true);
-    values.use_asynchronous_shaders.SetGlobal(true);
-    values.use_fast_gpu_time.SetGlobal(true);
-    values.use_vulkan_driver_pipeline_cache.SetGlobal(true);
-    values.bg_red.SetGlobal(true);
-    values.bg_green.SetGlobal(true);
-    values.bg_blue.SetGlobal(true);
-    values.enable_compute_pipelines.SetGlobal(true);
-    values.use_video_framerate.SetGlobal(true);
-
-    // System
-    values.language_index.SetGlobal(true);
-    values.region_index.SetGlobal(true);
-    values.time_zone_index.SetGlobal(true);
-    values.rng_seed.SetGlobal(true);
-    values.sound_index.SetGlobal(true);
-
-    // Controls
-    values.players.SetGlobal(true);
-    values.use_docked_mode.SetGlobal(true);
-    values.vibration_enabled.SetGlobal(true);
-    values.motion_enabled.SetGlobal(true);
+void SetConfiguringGlobal(bool is_global) {
+    configuring_global = is_global;
 }
 
 } // namespace Settings
diff --git a/src/common/settings.h b/src/common/settings.h
index 59e96e74fd..b0bc6519a6 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -6,95 +6,21 @@
 #include <algorithm>
 #include <array>
 #include <map>
-#include <optional>
+#include <memory>
+#include <stdexcept>
 #include <string>
 #include <utility>
 #include <vector>
 
 #include "common/common_types.h"
+#include "common/settings_common.h"
+#include "common/settings_enums.h"
 #include "common/settings_input.h"
+#include "common/settings_setting.h"
 
 namespace Settings {
 
-enum class VSyncMode : u32 {
-    Immediate = 0,
-    Mailbox = 1,
-    FIFO = 2,
-    FIFORelaxed = 3,
-};
-
-enum class RendererBackend : u32 {
-    OpenGL = 0,
-    Vulkan = 1,
-    Null = 2,
-};
-
-enum class ShaderBackend : u32 {
-    GLSL = 0,
-    GLASM = 1,
-    SPIRV = 2,
-};
-
-enum class GPUAccuracy : u32 {
-    Normal = 0,
-    High = 1,
-    Extreme = 2,
-};
-
-enum class CPUAccuracy : u32 {
-    Auto = 0,
-    Accurate = 1,
-    Unsafe = 2,
-    Paranoid = 3,
-};
-
-enum class FullscreenMode : u32 {
-    Borderless = 0,
-    Exclusive = 1,
-};
-
-enum class NvdecEmulation : u32 {
-    Off = 0,
-    CPU = 1,
-    GPU = 2,
-};
-
-enum class ResolutionSetup : u32 {
-    Res1_2X = 0,
-    Res3_4X = 1,
-    Res1X = 2,
-    Res3_2X = 3,
-    Res2X = 4,
-    Res3X = 5,
-    Res4X = 6,
-    Res5X = 7,
-    Res6X = 8,
-    Res7X = 9,
-    Res8X = 10,
-};
-
-enum class ScalingFilter : u32 {
-    NearestNeighbor = 0,
-    Bilinear = 1,
-    Bicubic = 2,
-    Gaussian = 3,
-    ScaleForce = 4,
-    Fsr = 5,
-    LastFilter = Fsr,
-};
-
-enum class AntiAliasing : u32 {
-    None = 0,
-    Fxaa = 1,
-    Smaa = 2,
-    LastAA = Smaa,
-};
-
-enum class AstcRecompression : u32 {
-    Uncompressed = 0,
-    Bc1 = 1,
-    Bc3 = 2,
-};
+const char* TranslateCategory(Settings::Category category);
 
 struct ResolutionScalingInfo {
     u32 up_scale{1};
@@ -119,239 +45,47 @@ struct ResolutionScalingInfo {
     }
 };
 
-/** The Setting class is a simple resource manager. It defines a label and default value alongside
- * the actual value of the setting for simpler and less-error prone use with frontend
- * configurations. Specifying a default value and label is required. A minimum and maximum range can
- * be specified for sanitization.
- */
-template <typename Type, bool ranged = false>
-class Setting {
-protected:
-    Setting() = default;
+#ifndef CANNOT_EXPLICITLY_INSTANTIATE
+// Instantiate the classes elsewhere (settings.cpp) to reduce compiler/linker work
+#define SETTING(TYPE, RANGED) extern template class Setting<TYPE, RANGED>
+#define SWITCHABLE(TYPE, RANGED) extern template class SwitchableSetting<TYPE, RANGED>
 
-    /**
-     * Only sets the setting to the given initializer, leaving the other members to their default
-     * initializers.
-     *
-     * @param global_val Initial value of the setting
-     */
-    explicit Setting(const Type& val) : value{val} {}
+SETTING(AudioEngine, false);
+SETTING(bool, false);
+SETTING(int, false);
+SETTING(s32, false);
+SETTING(std::string, false);
+SETTING(std::string, false);
+SETTING(u16, false);
+SWITCHABLE(AnisotropyMode, true);
+SWITCHABLE(AntiAliasing, false);
+SWITCHABLE(AspectRatio, true);
+SWITCHABLE(AstcDecodeMode, true);
+SWITCHABLE(AstcRecompression, true);
+SWITCHABLE(AudioMode, true);
+SWITCHABLE(CpuAccuracy, true);
+SWITCHABLE(FullscreenMode, true);
+SWITCHABLE(GpuAccuracy, true);
+SWITCHABLE(Language, true);
+SWITCHABLE(NvdecEmulation, false);
+SWITCHABLE(Region, true);
+SWITCHABLE(RendererBackend, true);
+SWITCHABLE(ScalingFilter, false);
+SWITCHABLE(ShaderBackend, true);
+SWITCHABLE(TimeZone, true);
+SETTING(VSyncMode, true);
+SWITCHABLE(bool, false);
+SWITCHABLE(int, false);
+SWITCHABLE(int, true);
+SWITCHABLE(s64, false);
+SWITCHABLE(u16, true);
+SWITCHABLE(u32, false);
+SWITCHABLE(u8, false);
+SWITCHABLE(u8, true);
 
-public:
-    /**
-     * Sets a default value, label, and setting value.
-     *
-     * @param default_val Initial value of the setting, and default value of the setting
-     * @param name Label for the setting
-     */
-    explicit Setting(const Type& default_val, const std::string& name)
-        requires(!ranged)
-        : value{default_val}, default_value{default_val}, label{name} {}
-    virtual ~Setting() = default;
-
-    /**
-     * Sets a default value, minimum value, maximum value, and label.
-     *
-     * @param default_val Initial value of the setting, and default value of the setting
-     * @param min_val Sets the minimum allowed value of the setting
-     * @param max_val Sets the maximum allowed value of the setting
-     * @param name Label for the setting
-     */
-    explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
-                     const std::string& name)
-        requires(ranged)
-        : value{default_val},
-          default_value{default_val}, maximum{max_val}, minimum{min_val}, label{name} {}
-
-    /**
-     *  Returns a reference to the setting's value.
-     *
-     * @returns A reference to the setting
-     */
-    [[nodiscard]] virtual const Type& GetValue() const {
-        return value;
-    }
-
-    /**
-     * Sets the setting to the given value.
-     *
-     * @param val The desired value
-     */
-    virtual void SetValue(const Type& val) {
-        Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
-        std::swap(value, temp);
-    }
-
-    /**
-     * Returns the value that this setting was created with.
-     *
-     * @returns A reference to the default value
-     */
-    [[nodiscard]] const Type& GetDefault() const {
-        return default_value;
-    }
-
-    /**
-     * Returns the label this setting was created with.
-     *
-     * @returns A reference to the label
-     */
-    [[nodiscard]] const std::string& GetLabel() const {
-        return label;
-    }
-
-    /**
-     * Assigns a value to the setting.
-     *
-     * @param val The desired setting value
-     *
-     * @returns A reference to the setting
-     */
-    virtual const Type& operator=(const Type& val) {
-        Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
-        std::swap(value, temp);
-        return value;
-    }
-
-    /**
-     * Returns a reference to the setting.
-     *
-     * @returns A reference to the setting
-     */
-    explicit virtual operator const Type&() const {
-        return value;
-    }
-
-protected:
-    Type value{};               ///< The setting
-    const Type default_value{}; ///< The default value
-    const Type maximum{};       ///< Maximum allowed value of the setting
-    const Type minimum{};       ///< Minimum allowed value of the setting
-    const std::string label{};  ///< The setting's label
-};
-
-/**
- * The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
- * custom setting to switch to when a guest application specifically requires it. The effect is that
- * other components of the emulator can access the setting's intended value without any need for the
- * component to ask whether the custom or global setting is needed at the moment.
- *
- * By default, the global setting is used.
- */
-template <typename Type, bool ranged = false>
-class SwitchableSetting : virtual public Setting<Type, ranged> {
-public:
-    /**
-     * Sets a default value, label, and setting value.
-     *
-     * @param default_val Initial value of the setting, and default value of the setting
-     * @param name Label for the setting
-     */
-    explicit SwitchableSetting(const Type& default_val, const std::string& name)
-        requires(!ranged)
-        : Setting<Type>{default_val, name} {}
-    virtual ~SwitchableSetting() = default;
-
-    /**
-     * Sets a default value, minimum value, maximum value, and label.
-     *
-     * @param default_val Initial value of the setting, and default value of the setting
-     * @param min_val Sets the minimum allowed value of the setting
-     * @param max_val Sets the maximum allowed value of the setting
-     * @param name Label for the setting
-     */
-    explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
-                               const std::string& name)
-        requires(ranged)
-        : Setting<Type, true>{default_val, min_val, max_val, name} {}
-
-    /**
-     * Tells this setting to represent either the global or custom setting when other member
-     * functions are used.
-     *
-     * @param to_global Whether to use the global or custom setting.
-     */
-    void SetGlobal(bool to_global) {
-        use_global = to_global;
-    }
-
-    /**
-     * Returns whether this setting is using the global setting or not.
-     *
-     * @returns The global state
-     */
-    [[nodiscard]] bool UsingGlobal() const {
-        return use_global;
-    }
-
-    /**
-     * Returns either the global or custom setting depending on the values of this setting's global
-     * state or if the global value was specifically requested.
-     *
-     * @param need_global Request global value regardless of setting's state; defaults to false
-     *
-     * @returns The required value of the setting
-     */
-    [[nodiscard]] virtual const Type& GetValue() const override {
-        if (use_global) {
-            return this->value;
-        }
-        return custom;
-    }
-    [[nodiscard]] virtual const Type& GetValue(bool need_global) const {
-        if (use_global || need_global) {
-            return this->value;
-        }
-        return custom;
-    }
-
-    /**
-     * Sets the current setting value depending on the global state.
-     *
-     * @param val The new value
-     */
-    void SetValue(const Type& val) override {
-        Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
-        if (use_global) {
-            std::swap(this->value, temp);
-        } else {
-            std::swap(custom, temp);
-        }
-    }
-
-    /**
-     * Assigns the current setting value depending on the global state.
-     *
-     * @param val The new value
-     *
-     * @returns A reference to the current setting value
-     */
-    const Type& operator=(const Type& val) override {
-        Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
-        if (use_global) {
-            std::swap(this->value, temp);
-            return this->value;
-        }
-        std::swap(custom, temp);
-        return custom;
-    }
-
-    /**
-     * Returns the current setting value depending on the global state.
-     *
-     * @returns A reference to the current setting value
-     */
-    virtual explicit operator const Type&() const override {
-        if (use_global) {
-            return this->value;
-        }
-        return custom;
-    }
-
-protected:
-    bool use_global{true}; ///< The setting's global state
-    Type custom{};         ///< The custom value of the setting
-};
+#undef SETTING
+#undef SWITCHABLE
+#endif
 
 /**
  * The InputSetting class allows for getting a reference to either the global or custom members.
@@ -391,208 +125,388 @@ struct TouchFromButtonMap {
 };
 
 struct Values {
+    Linkage linkage{};
+
     // Audio
-    Setting<std::string> sink_id{"auto", "output_engine"};
-    Setting<std::string> audio_output_device_id{"auto", "output_device"};
-    Setting<std::string> audio_input_device_id{"auto", "input_device"};
-    Setting<bool> audio_muted{false, "audio_muted"};
-    SwitchableSetting<u8, true> volume{100, 0, 200, "volume"};
-    Setting<bool> dump_audio_commands{false, "dump_audio_commands"};
+    Setting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine", Category::Audio,
+                                 Specialization::RuntimeList};
+    Setting<std::string> audio_output_device_id{linkage, "auto", "output_device", Category::Audio,
+                                                Specialization::RuntimeList};
+    Setting<std::string> audio_input_device_id{linkage, "auto", "input_device", Category::Audio,
+                                               Specialization::RuntimeList};
+    SwitchableSetting<AudioMode, true> sound_index{
+        linkage,       AudioMode::Stereo,     AudioMode::Mono,         AudioMode::Surround,
+        "sound_index", Category::SystemAudio, Specialization::Default, true,
+        true};
+    SwitchableSetting<u8, true> volume{linkage,
+                                       100,
+                                       0,
+                                       200,
+                                       "volume",
+                                       Category::Audio,
+                                       Specialization::Scalar | Specialization::Percentage,
+                                       true,
+                                       true};
+    Setting<bool, false> audio_muted{
+        linkage, false, "audio_muted", Category::Audio, Specialization::Default, false, true};
+    Setting<bool, false> dump_audio_commands{
+        linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
 
     // Core
-    SwitchableSetting<bool> use_multi_core{true, "use_multi_core"};
-    SwitchableSetting<bool> use_unsafe_extended_memory_layout{false,
-                                                              "use_unsafe_extended_memory_layout"};
+    SwitchableSetting<bool> use_multi_core{linkage, true, "use_multi_core", Category::Core};
+    SwitchableSetting<MemoryLayout, true> memory_layout_mode{linkage,
+                                                             MemoryLayout::Memory_4Gb,
+                                                             MemoryLayout::Memory_4Gb,
+                                                             MemoryLayout::Memory_8Gb,
+                                                             "memory_layout_mode",
+                                                             Category::Core};
+    SwitchableSetting<bool> use_speed_limit{
+        linkage, true, "use_speed_limit", Category::Core, Specialization::Paired, false, true};
+    SwitchableSetting<u16, true> speed_limit{linkage,
+                                             100,
+                                             0,
+                                             9999,
+                                             "speed_limit",
+                                             Category::Core,
+                                             Specialization::Countable | Specialization::Percentage,
+                                             true,
+                                             true,
+                                             &use_speed_limit};
 
     // Cpu
-    SwitchableSetting<CPUAccuracy, true> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto,
-                                                      CPUAccuracy::Paranoid, "cpu_accuracy"};
-    // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
-    Setting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
-    Setting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
+    SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage,           CpuAccuracy::Auto,
+                                                      CpuAccuracy::Auto, CpuAccuracy::Paranoid,
+                                                      "cpu_accuracy",    Category::Cpu};
+    Setting<bool> cpu_debug_mode{linkage, false, "cpu_debug_mode", Category::CpuDebug};
 
-    Setting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
-    Setting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
-    Setting<bool> cpuopt_return_stack_buffer{true, "cpuopt_return_stack_buffer"};
-    Setting<bool> cpuopt_fast_dispatcher{true, "cpuopt_fast_dispatcher"};
-    Setting<bool> cpuopt_context_elimination{true, "cpuopt_context_elimination"};
-    Setting<bool> cpuopt_const_prop{true, "cpuopt_const_prop"};
-    Setting<bool> cpuopt_misc_ir{true, "cpuopt_misc_ir"};
-    Setting<bool> cpuopt_reduce_misalign_checks{true, "cpuopt_reduce_misalign_checks"};
-    Setting<bool> cpuopt_fastmem{true, "cpuopt_fastmem"};
-    Setting<bool> cpuopt_fastmem_exclusives{true, "cpuopt_fastmem_exclusives"};
-    Setting<bool> cpuopt_recompile_exclusives{true, "cpuopt_recompile_exclusives"};
-    Setting<bool> cpuopt_ignore_memory_aborts{true, "cpuopt_ignore_memory_aborts"};
+    Setting<bool> cpuopt_page_tables{linkage, true, "cpuopt_page_tables", Category::CpuDebug};
+    Setting<bool> cpuopt_block_linking{linkage, true, "cpuopt_block_linking", Category::CpuDebug};
+    Setting<bool> cpuopt_return_stack_buffer{linkage, true, "cpuopt_return_stack_buffer",
+                                             Category::CpuDebug};
+    Setting<bool> cpuopt_fast_dispatcher{linkage, true, "cpuopt_fast_dispatcher",
+                                         Category::CpuDebug};
+    Setting<bool> cpuopt_context_elimination{linkage, true, "cpuopt_context_elimination",
+                                             Category::CpuDebug};
+    Setting<bool> cpuopt_const_prop{linkage, true, "cpuopt_const_prop", Category::CpuDebug};
+    Setting<bool> cpuopt_misc_ir{linkage, true, "cpuopt_misc_ir", Category::CpuDebug};
+    Setting<bool> cpuopt_reduce_misalign_checks{linkage, true, "cpuopt_reduce_misalign_checks",
+                                                Category::CpuDebug};
+    Setting<bool> cpuopt_fastmem{linkage, true, "cpuopt_fastmem", Category::CpuDebug};
+    Setting<bool> cpuopt_fastmem_exclusives{linkage, true, "cpuopt_fastmem_exclusives",
+                                            Category::CpuDebug};
+    Setting<bool> cpuopt_recompile_exclusives{linkage, true, "cpuopt_recompile_exclusives",
+                                              Category::CpuDebug};
+    Setting<bool> cpuopt_ignore_memory_aborts{linkage, true, "cpuopt_ignore_memory_aborts",
+                                              Category::CpuDebug};
 
-    SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{true, "cpuopt_unsafe_unfuse_fma"};
-    SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{true, "cpuopt_unsafe_reduce_fp_error"};
+    SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{linkage, true, "cpuopt_unsafe_unfuse_fma",
+                                                     Category::CpuUnsafe};
+    SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{
+        linkage, true, "cpuopt_unsafe_reduce_fp_error", Category::CpuUnsafe};
     SwitchableSetting<bool> cpuopt_unsafe_ignore_standard_fpcr{
-        true, "cpuopt_unsafe_ignore_standard_fpcr"};
-    SwitchableSetting<bool> cpuopt_unsafe_inaccurate_nan{true, "cpuopt_unsafe_inaccurate_nan"};
-    SwitchableSetting<bool> cpuopt_unsafe_fastmem_check{true, "cpuopt_unsafe_fastmem_check"};
+        linkage, true, "cpuopt_unsafe_ignore_standard_fpcr", Category::CpuUnsafe};
+    SwitchableSetting<bool> cpuopt_unsafe_inaccurate_nan{
+        linkage, true, "cpuopt_unsafe_inaccurate_nan", Category::CpuUnsafe};
+    SwitchableSetting<bool> cpuopt_unsafe_fastmem_check{
+        linkage, true, "cpuopt_unsafe_fastmem_check", Category::CpuUnsafe};
     SwitchableSetting<bool> cpuopt_unsafe_ignore_global_monitor{
-        true, "cpuopt_unsafe_ignore_global_monitor"};
+        linkage, true, "cpuopt_unsafe_ignore_global_monitor", Category::CpuUnsafe};
 
     // Renderer
     SwitchableSetting<RendererBackend, true> renderer_backend{
-        RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"};
-    SwitchableSetting<bool> async_presentation{false, "async_presentation"};
-    SwitchableSetting<bool> renderer_force_max_clock{false, "force_max_clock"};
-    Setting<bool> renderer_debug{false, "debug"};
-    Setting<bool> renderer_shader_feedback{false, "shader_feedback"};
-    Setting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
-    Setting<bool> disable_shader_loop_safety_checks{false, "disable_shader_loop_safety_checks"};
-    SwitchableSetting<int> vulkan_device{0, "vulkan_device"};
+        linkage,   RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null,
+        "backend", Category::Renderer};
+    SwitchableSetting<ShaderBackend, true> shader_backend{
+        linkage,          ShaderBackend::Glsl, ShaderBackend::Glsl,        ShaderBackend::SpirV,
+        "shader_backend", Category::Renderer,  Specialization::RuntimeList};
+    SwitchableSetting<int> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer,
+                                         Specialization::RuntimeList};
 
-    ResolutionScalingInfo resolution_info{};
-    SwitchableSetting<ResolutionSetup> resolution_setup{ResolutionSetup::Res1X, "resolution_setup"};
-    SwitchableSetting<ScalingFilter> scaling_filter{ScalingFilter::Bilinear, "scaling_filter"};
-    SwitchableSetting<int, true> fsr_sharpening_slider{25, 0, 200, "fsr_sharpening_slider"};
-    SwitchableSetting<AntiAliasing> anti_aliasing{AntiAliasing::None, "anti_aliasing"};
+    SwitchableSetting<bool> use_disk_shader_cache{linkage, true, "use_disk_shader_cache",
+                                                  Category::Renderer};
+    SwitchableSetting<bool> use_asynchronous_gpu_emulation{
+        linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
+    SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage,
+                                                            AstcDecodeMode::Gpu,
+                                                            AstcDecodeMode::Cpu,
+                                                            AstcDecodeMode::CpuAsynchronous,
+                                                            "accelerate_astc",
+                                                            Category::Renderer};
+    Setting<VSyncMode, true> vsync_mode{
+        linkage,     VSyncMode::Fifo,    VSyncMode::Immediate,        VSyncMode::FifoRelaxed,
+        "use_vsync", Category::Renderer, Specialization::RuntimeList, true,
+        true};
+    SwitchableSetting<NvdecEmulation> nvdec_emulation{linkage, NvdecEmulation::Gpu,
+                                                      "nvdec_emulation", Category::Renderer};
     // *nix platforms may have issues with the borderless windowed fullscreen mode.
     // Default to exclusive fullscreen on these platforms for now.
-    SwitchableSetting<FullscreenMode, true> fullscreen_mode{
+    SwitchableSetting<FullscreenMode, true> fullscreen_mode{linkage,
 #ifdef _WIN32
-        FullscreenMode::Borderless,
+                                                            FullscreenMode::Borderless,
 #else
-        FullscreenMode::Exclusive,
+                                                            FullscreenMode::Exclusive,
 #endif
-        FullscreenMode::Borderless, FullscreenMode::Exclusive, "fullscreen_mode"};
-    SwitchableSetting<int, true> aspect_ratio{0, 0, 4, "aspect_ratio"};
-    SwitchableSetting<int, true> max_anisotropy{0, 0, 5, "max_anisotropy"};
-    SwitchableSetting<bool> use_speed_limit{true, "use_speed_limit"};
-    SwitchableSetting<u16, true> speed_limit{100, 0, 9999, "speed_limit"};
-    SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
-    SwitchableSetting<GPUAccuracy, true> gpu_accuracy{GPUAccuracy::High, GPUAccuracy::Normal,
-                                                      GPUAccuracy::Extreme, "gpu_accuracy"};
-    SwitchableSetting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
-    SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"};
-    SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"};
-    SwitchableSetting<bool> async_astc{false, "async_astc"};
-    Setting<VSyncMode, true> vsync_mode{VSyncMode::FIFO, VSyncMode::Immediate,
-                                        VSyncMode::FIFORelaxed, "use_vsync"};
-    SwitchableSetting<bool> use_reactive_flushing{true, "use_reactive_flushing"};
-    SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL,
-                                                          ShaderBackend::SPIRV, "shader_backend"};
-    SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
-    SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
-    SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{true,
-                                                             "use_vulkan_driver_pipeline_cache"};
-    SwitchableSetting<bool> enable_compute_pipelines{false, "enable_compute_pipelines"};
-    SwitchableSetting<AstcRecompression, true> astc_recompression{
-        AstcRecompression::Uncompressed, AstcRecompression::Uncompressed, AstcRecompression::Bc3,
-        "astc_recompression"};
-    SwitchableSetting<bool> use_video_framerate{false, "use_video_framerate"};
-    SwitchableSetting<bool> barrier_feedback_loops{true, "barrier_feedback_loops"};
+                                                            FullscreenMode::Borderless,
+                                                            FullscreenMode::Exclusive,
+                                                            "fullscreen_mode",
+                                                            Category::Renderer,
+                                                            Specialization::Default,
+                                                            true,
+                                                            true};
+    SwitchableSetting<AspectRatio, true> aspect_ratio{linkage,
+                                                      AspectRatio::R16_9,
+                                                      AspectRatio::R16_9,
+                                                      AspectRatio::Stretch,
+                                                      "aspect_ratio",
+                                                      Category::Renderer,
+                                                      Specialization::Default,
+                                                      true,
+                                                      true};
 
-    SwitchableSetting<u8> bg_red{0, "bg_red"};
-    SwitchableSetting<u8> bg_green{0, "bg_green"};
-    SwitchableSetting<u8> bg_blue{0, "bg_blue"};
+    ResolutionScalingInfo resolution_info{};
+    SwitchableSetting<ResolutionSetup> resolution_setup{linkage, ResolutionSetup::Res1X,
+                                                        "resolution_setup", Category::Renderer};
+    SwitchableSetting<ScalingFilter> scaling_filter{linkage,
+                                                    ScalingFilter::Bilinear,
+                                                    "scaling_filter",
+                                                    Category::Renderer,
+                                                    Specialization::Default,
+                                                    true,
+                                                    true};
+    SwitchableSetting<AntiAliasing> anti_aliasing{linkage,
+                                                  AntiAliasing::None,
+                                                  "anti_aliasing",
+                                                  Category::Renderer,
+                                                  Specialization::Default,
+                                                  true,
+                                                  true};
+    SwitchableSetting<int, true> fsr_sharpening_slider{linkage,
+                                                       25,
+                                                       0,
+                                                       200,
+                                                       "fsr_sharpening_slider",
+                                                       Category::Renderer,
+                                                       Specialization::Scalar |
+                                                           Specialization::Percentage,
+                                                       true,
+                                                       true};
+
+    SwitchableSetting<u8, false> bg_red{
+        linkage, 0, "bg_red", Category::Renderer, Specialization::Default, true, true};
+    SwitchableSetting<u8, false> bg_green{
+        linkage, 0, "bg_green", Category::Renderer, Specialization::Default, true, true};
+    SwitchableSetting<u8, false> bg_blue{
+        linkage, 0, "bg_blue", Category::Renderer, Specialization::Default, true, true};
+
+    SwitchableSetting<GpuAccuracy, true> gpu_accuracy{linkage,
+                                                      GpuAccuracy::High,
+                                                      GpuAccuracy::Normal,
+                                                      GpuAccuracy::Extreme,
+                                                      "gpu_accuracy",
+                                                      Category::RendererAdvanced,
+                                                      Specialization::Default,
+                                                      true,
+                                                      true};
+    SwitchableSetting<AnisotropyMode, true> max_anisotropy{
+        linkage,          AnisotropyMode::Automatic, AnisotropyMode::Automatic, AnisotropyMode::X16,
+        "max_anisotropy", Category::RendererAdvanced};
+    SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
+                                                                  AstcRecompression::Uncompressed,
+                                                                  AstcRecompression::Uncompressed,
+                                                                  AstcRecompression::Bc3,
+                                                                  "astc_recompression",
+                                                                  Category::RendererAdvanced};
+    SwitchableSetting<bool> async_presentation{linkage, false, "async_presentation",
+                                               Category::RendererAdvanced};
+    SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock",
+                                                     Category::RendererAdvanced};
+    SwitchableSetting<bool> use_reactive_flushing{linkage, true, "use_reactive_flushing",
+                                                  Category::RendererAdvanced};
+    SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
+                                                     Category::RendererAdvanced};
+    SwitchableSetting<bool> use_fast_gpu_time{
+        linkage, true, "use_fast_gpu_time", Category::RendererAdvanced, Specialization::Default,
+        true,    true};
+    SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{linkage,
+                                                             true,
+                                                             "use_vulkan_driver_pipeline_cache",
+                                                             Category::RendererAdvanced,
+                                                             Specialization::Default,
+                                                             true,
+                                                             true};
+    SwitchableSetting<bool> enable_compute_pipelines{linkage, false, "enable_compute_pipelines",
+                                                     Category::RendererAdvanced};
+    SwitchableSetting<bool> use_video_framerate{linkage, false, "use_video_framerate",
+                                                Category::RendererAdvanced};
+    SwitchableSetting<bool> barrier_feedback_loops{linkage, true, "barrier_feedback_loops",
+                                                   Category::RendererAdvanced};
+
+    Setting<bool> renderer_debug{linkage, false, "debug", Category::RendererDebug};
+    Setting<bool> renderer_shader_feedback{linkage, false, "shader_feedback",
+                                           Category::RendererDebug};
+    Setting<bool> enable_nsight_aftermath{linkage, false, "nsight_aftermath",
+                                          Category::RendererDebug};
+    Setting<bool> disable_shader_loop_safety_checks{
+        linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug};
 
     // System
-    SwitchableSetting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
-    Setting<std::string> device_name{"Yuzu", "device_name"};
+    SwitchableSetting<Language, true> language_index{linkage,
+                                                     Language::EnglishAmerican,
+                                                     Language::Japanese,
+                                                     Language::PortugueseBrazilian,
+                                                     "language_index",
+                                                     Category::System};
+    SwitchableSetting<Region, true> region_index{linkage,        Region::Usa,    Region::Japan,
+                                                 Region::Taiwan, "region_index", Category::System};
+    SwitchableSetting<TimeZone, true> time_zone_index{linkage,           TimeZone::Auto,
+                                                      TimeZone::Auto,    TimeZone::Zulu,
+                                                      "time_zone_index", Category::System};
     // Measured in seconds since epoch
-    std::optional<s64> custom_rtc;
+    SwitchableSetting<bool> custom_rtc_enabled{
+        linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
+    SwitchableSetting<s64> custom_rtc{
+        linkage, 0,    "custom_rtc",       Category::System, Specialization::Time,
+        true,    true, &custom_rtc_enabled};
     // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
     s64 custom_rtc_differential;
+    SwitchableSetting<bool> rng_seed_enabled{
+        linkage, false, "rng_seed_enabled", Category::System, Specialization::Paired, true, true};
+    SwitchableSetting<u32> rng_seed{
+        linkage, 0,    "rng_seed",       Category::System, Specialization::Hex,
+        true,    true, &rng_seed_enabled};
+    Setting<std::string> device_name{
+        linkage, "yuzu", "device_name", Category::System, Specialization::Default, true, true};
 
-    Setting<s32> current_user{0, "current_user"};
-    SwitchableSetting<s32, true> language_index{1, 0, 17, "language_index"};
-    SwitchableSetting<s32, true> region_index{1, 0, 6, "region_index"};
-    SwitchableSetting<s32, true> time_zone_index{0, 0, 45, "time_zone_index"};
-    SwitchableSetting<s32, true> sound_index{1, 0, 2, "sound_index"};
+    Setting<s32> current_user{linkage, 0, "current_user", Category::System};
+
+    SwitchableSetting<bool> use_docked_mode{linkage, true, "use_docked_mode", Category::System};
 
     // Controls
     InputSetting<std::array<PlayerInput, 10>> players;
 
-    SwitchableSetting<bool> use_docked_mode{true, "use_docked_mode"};
+    Setting<bool> enable_raw_input{
+        linkage, false, "enable_raw_input", Category::Controls, Specialization::Default,
+// Only read/write enable_raw_input on Windows platforms
+#ifdef _WIN32
+        true
+#else
+        false
+#endif
+    };
+    Setting<bool> controller_navigation{linkage, true, "controller_navigation", Category::Controls};
+    Setting<bool> enable_joycon_driver{linkage, true, "enable_joycon_driver", Category::Controls};
+    Setting<bool> enable_procon_driver{linkage, false, "enable_procon_driver", Category::Controls};
 
-    Setting<bool> enable_raw_input{false, "enable_raw_input"};
-    Setting<bool> controller_navigation{true, "controller_navigation"};
-    Setting<bool> enable_joycon_driver{true, "enable_joycon_driver"};
-    Setting<bool> enable_procon_driver{false, "enable_procon_driver"};
+    SwitchableSetting<bool> vibration_enabled{linkage, true, "vibration_enabled",
+                                              Category::Controls};
+    SwitchableSetting<bool> enable_accurate_vibrations{linkage, false, "enable_accurate_vibrations",
+                                                       Category::Controls};
 
-    SwitchableSetting<bool> vibration_enabled{true, "vibration_enabled"};
-    SwitchableSetting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
+    SwitchableSetting<bool> motion_enabled{linkage, true, "motion_enabled", Category::Controls};
+    Setting<std::string> udp_input_servers{linkage, "127.0.0.1:26760", "udp_input_servers",
+                                           Category::Controls};
+    Setting<bool> enable_udp_controller{linkage, false, "enable_udp_controller",
+                                        Category::Controls};
 
-    SwitchableSetting<bool> motion_enabled{true, "motion_enabled"};
-    Setting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"};
-    Setting<bool> enable_udp_controller{false, "enable_udp_controller"};
+    Setting<bool> pause_tas_on_load{linkage, true, "pause_tas_on_load", Category::Controls};
+    Setting<bool> tas_enable{linkage, false, "tas_enable", Category::Controls};
+    Setting<bool> tas_loop{linkage, false, "tas_loop", Category::Controls};
 
-    Setting<bool> pause_tas_on_load{true, "pause_tas_on_load"};
-    Setting<bool> tas_enable{false, "tas_enable"};
-    Setting<bool> tas_loop{false, "tas_loop"};
+    Setting<bool> mouse_panning{
+        linkage, false, "mouse_panning", Category::Controls, Specialization::Default, false};
+    Setting<u8, true> mouse_panning_sensitivity{
+        linkage, 50, 1, 100, "mouse_panning_sensitivity", Category::Controls};
+    Setting<bool> mouse_enabled{linkage, false, "mouse_enabled", Category::Controls};
 
-    Setting<bool> mouse_panning{false, "mouse_panning"};
-    Setting<u8, true> mouse_panning_x_sensitivity{50, 1, 100, "mouse_panning_x_sensitivity"};
-    Setting<u8, true> mouse_panning_y_sensitivity{50, 1, 100, "mouse_panning_y_sensitivity"};
-    Setting<u8, true> mouse_panning_deadzone_counterweight{20, 0, 100,
-                                                           "mouse_panning_deadzone_counterweight"};
-    Setting<u8, true> mouse_panning_decay_strength{18, 0, 100, "mouse_panning_decay_strength"};
-    Setting<u8, true> mouse_panning_min_decay{6, 0, 100, "mouse_panning_min_decay"};
+    Setting<u8, true> mouse_panning_x_sensitivity{
+        linkage, 50, 1, 100, "mouse_panning_x_sensitivity", Category::Controls};
+    Setting<u8, true> mouse_panning_y_sensitivity{
+        linkage, 50, 1, 100, "mouse_panning_y_sensitivity", Category::Controls};
+    Setting<u8, true> mouse_panning_deadzone_counterweight{
+        linkage, 20, 0, 100, "mouse_panning_deadzone_counterweight", Category::Controls};
+    Setting<u8, true> mouse_panning_decay_strength{
+        linkage, 18, 0, 100, "mouse_panning_decay_strength", Category::Controls};
+    Setting<u8, true> mouse_panning_min_decay{
+        linkage, 6, 0, 100, "mouse_panning_min_decay", Category::Controls};
 
-    Setting<bool> mouse_enabled{false, "mouse_enabled"};
-    Setting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
-    Setting<bool> keyboard_enabled{false, "keyboard_enabled"};
+    Setting<bool> emulate_analog_keyboard{linkage, false, "emulate_analog_keyboard",
+                                          Category::Controls};
+    Setting<bool> keyboard_enabled{linkage, false, "keyboard_enabled", Category::Controls};
 
-    Setting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
+    Setting<bool> debug_pad_enabled{linkage, false, "debug_pad_enabled", Category::Controls};
     ButtonsRaw debug_pad_buttons;
     AnalogsRaw debug_pad_analogs;
 
     TouchscreenInput touchscreen;
 
-    Setting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850", "touch_device"};
-    Setting<int> touch_from_button_map_index{0, "touch_from_button_map"};
+    Setting<std::string> touch_device{linkage, "min_x:100,min_y:50,max_x:1800,max_y:850",
+                                      "touch_device", Category::Controls};
+    Setting<int> touch_from_button_map_index{linkage, 0, "touch_from_button_map",
+                                             Category::Controls};
     std::vector<TouchFromButtonMap> touch_from_button_maps;
 
-    Setting<bool> enable_ring_controller{true, "enable_ring_controller"};
+    Setting<bool> enable_ring_controller{linkage, true, "enable_ring_controller",
+                                         Category::Controls};
     RingconRaw ringcon_analogs;
 
-    Setting<bool> enable_ir_sensor{false, "enable_ir_sensor"};
-    Setting<std::string> ir_sensor_device{"auto", "ir_sensor_device"};
+    Setting<bool> enable_ir_sensor{linkage, false, "enable_ir_sensor", Category::Controls};
+    Setting<std::string> ir_sensor_device{linkage, "auto", "ir_sensor_device", Category::Controls};
 
-    Setting<bool> random_amiibo_id{false, "random_amiibo_id"};
+    Setting<bool> random_amiibo_id{linkage, false, "random_amiibo_id", Category::Controls};
 
     // Data Storage
-    Setting<bool> use_virtual_sd{true, "use_virtual_sd"};
-    Setting<bool> gamecard_inserted{false, "gamecard_inserted"};
-    Setting<bool> gamecard_current_game{false, "gamecard_current_game"};
-    Setting<std::string> gamecard_path{std::string(), "gamecard_path"};
+    Setting<bool> use_virtual_sd{linkage, true, "use_virtual_sd", Category::DataStorage};
+    Setting<bool> gamecard_inserted{linkage, false, "gamecard_inserted", Category::DataStorage};
+    Setting<bool> gamecard_current_game{linkage, false, "gamecard_current_game",
+                                        Category::DataStorage};
+    Setting<std::string> gamecard_path{linkage, std::string(), "gamecard_path",
+                                       Category::DataStorage};
 
     // Debugging
     bool record_frame_times;
-    Setting<bool> use_gdbstub{false, "use_gdbstub"};
-    Setting<u16> gdbstub_port{6543, "gdbstub_port"};
-    Setting<std::string> program_args{std::string(), "program_args"};
-    Setting<bool> dump_exefs{false, "dump_exefs"};
-    Setting<bool> dump_nso{false, "dump_nso"};
-    Setting<bool> dump_shaders{false, "dump_shaders"};
-    Setting<bool> dump_macros{false, "dump_macros"};
-    Setting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
-    Setting<bool> reporting_services{false, "reporting_services"};
-    Setting<bool> quest_flag{false, "quest_flag"};
-    Setting<bool> disable_macro_jit{false, "disable_macro_jit"};
-    Setting<bool> disable_macro_hle{false, "disable_macro_hle"};
-    Setting<bool> extended_logging{false, "extended_logging"};
-    Setting<bool> use_debug_asserts{false, "use_debug_asserts"};
-    Setting<bool> use_auto_stub{false, "use_auto_stub"};
-    Setting<bool> enable_all_controllers{false, "enable_all_controllers"};
-    Setting<bool> create_crash_dumps{false, "create_crash_dumps"};
-    Setting<bool> perform_vulkan_check{true, "perform_vulkan_check"};
+    Setting<bool> use_gdbstub{linkage, false, "use_gdbstub", Category::Debugging};
+    Setting<u16> gdbstub_port{linkage, 6543, "gdbstub_port", Category::Debugging};
+    Setting<std::string> program_args{linkage, std::string(), "program_args", Category::Debugging};
+    Setting<bool> dump_exefs{linkage, false, "dump_exefs", Category::Debugging};
+    Setting<bool> dump_nso{linkage, false, "dump_nso", Category::Debugging};
+    Setting<bool> dump_shaders{
+        linkage, false, "dump_shaders", Category::DebuggingGraphics, Specialization::Default,
+        false};
+    Setting<bool> dump_macros{
+        linkage, false, "dump_macros", Category::DebuggingGraphics, Specialization::Default, false};
+    Setting<bool> enable_fs_access_log{linkage, false, "enable_fs_access_log", Category::Debugging};
+    Setting<bool> reporting_services{
+        linkage, false, "reporting_services", Category::Debugging, Specialization::Default, false};
+    Setting<bool> quest_flag{linkage, false, "quest_flag", Category::Debugging};
+    Setting<bool> disable_macro_jit{linkage, false, "disable_macro_jit",
+                                    Category::DebuggingGraphics};
+    Setting<bool> disable_macro_hle{linkage, false, "disable_macro_hle",
+                                    Category::DebuggingGraphics};
+    Setting<bool> extended_logging{
+        linkage, false, "extended_logging", Category::Debugging, Specialization::Default, false};
+    Setting<bool> use_debug_asserts{linkage, false, "use_debug_asserts", Category::Debugging};
+    Setting<bool> use_auto_stub{
+        linkage, false, "use_auto_stub", Category::Debugging, Specialization::Default, false};
+    Setting<bool> enable_all_controllers{linkage, false, "enable_all_controllers",
+                                         Category::Debugging};
+    Setting<bool> create_crash_dumps{linkage, false, "create_crash_dumps", Category::Debugging};
+    Setting<bool> perform_vulkan_check{linkage, true, "perform_vulkan_check", Category::Debugging};
 
     // Miscellaneous
-    Setting<std::string> log_filter{"*:Info", "log_filter"};
-    Setting<bool> use_dev_keys{false, "use_dev_keys"};
+    Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous};
+    Setting<bool> use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous};
 
     // Network
-    Setting<std::string> network_interface{std::string(), "network_interface"};
+    Setting<std::string> network_interface{linkage, std::string(), "network_interface",
+                                           Category::Network};
 
     // WebService
-    Setting<bool> enable_telemetry{true, "enable_telemetry"};
-    Setting<std::string> web_api_url{"https://api.yuzu-emu.org", "web_api_url"};
-    Setting<std::string> yuzu_username{std::string(), "yuzu_username"};
-    Setting<std::string> yuzu_token{std::string(), "yuzu_token"};
+    Setting<bool> enable_telemetry{linkage, true, "enable_telemetry", Category::WebService};
+    Setting<std::string> web_api_url{linkage, "https://api.yuzu-emu.org", "web_api_url",
+                                     Category::WebService};
+    Setting<std::string> yuzu_username{linkage, std::string(), "yuzu_username",
+                                       Category::WebService};
+    Setting<std::string> yuzu_token{linkage, std::string(), "yuzu_token", Category::WebService};
 
     // Add-Ons
     std::map<u64, std::vector<std::string>> disabled_addons;
@@ -600,9 +514,6 @@ struct Values {
 
 extern Values values;
 
-bool IsConfiguringGlobal();
-void SetConfiguringGlobal(bool is_global);
-
 bool IsGPULevelExtreme();
 bool IsGPULevelHigh();
 
@@ -610,7 +521,7 @@ bool IsFastmemEnabled();
 
 float Volume();
 
-std::string GetTimeZoneString();
+std::string GetTimeZoneString(TimeZone time_zone);
 
 void LogSettings();
 
@@ -619,4 +530,7 @@ void UpdateRescalingInfo();
 // Restore the global state of all applicable settings in the Values struct
 void RestoreGlobalState(bool is_powered_on);
 
+bool IsConfiguringGlobal();
+void SetConfiguringGlobal(bool is_global);
+
 } // namespace Settings
diff --git a/src/common/settings_common.cpp b/src/common/settings_common.cpp
new file mode 100644
index 0000000000..dedf5ef909
--- /dev/null
+++ b/src/common/settings_common.cpp
@@ -0,0 +1,58 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <string>
+#include "common/settings_common.h"
+
+namespace Settings {
+
+BasicSetting::BasicSetting(Linkage& linkage, const std::string& name, enum Category category_,
+                           bool save_, bool runtime_modifiable_, u32 specialization_,
+                           BasicSetting* other_setting_)
+    : label{name}, category{category_}, id{linkage.count}, save{save_},
+      runtime_modifiable{runtime_modifiable_}, specialization{specialization_},
+      other_setting{other_setting_} {
+    linkage.by_category[category].push_back(this);
+    linkage.count++;
+}
+
+BasicSetting::~BasicSetting() = default;
+
+std::string BasicSetting::ToStringGlobal() const {
+    return this->ToString();
+}
+
+bool BasicSetting::UsingGlobal() const {
+    return true;
+}
+
+void BasicSetting::SetGlobal(bool global) {}
+
+bool BasicSetting::Save() const {
+    return save;
+}
+
+bool BasicSetting::RuntimeModfiable() const {
+    return runtime_modifiable;
+}
+
+Category BasicSetting::GetCategory() const {
+    return category;
+}
+
+u32 BasicSetting::Specialization() const {
+    return specialization;
+}
+
+BasicSetting* BasicSetting::PairedSetting() const {
+    return other_setting;
+}
+
+const std::string& BasicSetting::GetLabel() const {
+    return label;
+}
+
+Linkage::Linkage(u32 initial_count) : count{initial_count} {}
+Linkage::~Linkage() = default;
+
+} // namespace Settings
diff --git a/src/common/settings_common.h b/src/common/settings_common.h
new file mode 100644
index 0000000000..2efb329b07
--- /dev/null
+++ b/src/common/settings_common.h
@@ -0,0 +1,256 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <functional>
+#include <map>
+#include <string>
+#include <typeindex>
+#include "common/common_types.h"
+
+namespace Settings {
+
+enum class Category : u32 {
+    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,
+};
+
+constexpr u8 SpecializationTypeMask = 0xf;
+constexpr u8 SpecializationAttributeMask = 0xf0;
+constexpr u8 SpecializationAttributeOffset = 4;
+
+// Scalar and countable could have better names
+enum Specialization : u8 {
+    Default = 0,
+    Time = 1,        // Duration or specific moment in time
+    Hex = 2,         // Hexadecimal number
+    List = 3,        // Setting has specific members
+    RuntimeList = 4, // Members of the list are determined during runtime
+    Scalar = 5,      // Values are continuous
+    Countable = 6,   // Can be stepped through
+    Paired = 7,      // Another setting is associated with this setting
+
+    Percentage = (1 << SpecializationAttributeOffset), // Should be represented as a percentage
+};
+
+class BasicSetting;
+
+class Linkage {
+public:
+    explicit Linkage(u32 initial_count = 0);
+    ~Linkage();
+    std::map<Category, std::vector<BasicSetting*>> by_category{};
+    std::vector<std::function<void()>> restore_functions{};
+    u32 count;
+};
+
+/**
+ * BasicSetting is an abstract class that only keeps track of metadata. The string methods are
+ * available to get data values out.
+ */
+class BasicSetting {
+protected:
+    explicit BasicSetting(Linkage& linkage, const std::string& name, Category category_, bool save_,
+                          bool runtime_modifiable_, u32 specialization,
+                          BasicSetting* other_setting);
+
+public:
+    virtual ~BasicSetting();
+
+    /*
+     * Data retrieval
+     */
+
+    /**
+     * Returns a string representation of the internal data. If the Setting is Switchable, it
+     * respects the internal global state: it is based on GetValue().
+     *
+     * @returns A string representation of the internal data.
+     */
+    [[nodiscard]] virtual std::string ToString() const = 0;
+
+    /**
+     * Returns a string representation of the global version of internal data. If the Setting is
+     * not Switchable, it behaves like ToString.
+     *
+     * @returns A string representation of the global version of internal data.
+     */
+    [[nodiscard]] virtual std::string ToStringGlobal() const;
+
+    /**
+     * @returns A string representation of the Setting's default value.
+     */
+    [[nodiscard]] virtual std::string DefaultToString() const = 0;
+
+    /**
+     * Returns a string representation of the minimum value of the setting. If the Setting is not
+     * ranged, the string represents the default initialization of the data type.
+     *
+     * @returns A string representation of the minimum value of the setting.
+     */
+    [[nodiscard]] virtual std::string MinVal() const = 0;
+
+    /**
+     * Returns a string representation of the maximum value of the setting. If the Setting is not
+     * ranged, the string represents the default initialization of the data type.
+     *
+     * @returns A string representation of the maximum value of the setting.
+     */
+    [[nodiscard]] virtual std::string MaxVal() const = 0;
+
+    /**
+     * Takes a string input, converts it to the internal data type if necessary, and then runs
+     * SetValue with it.
+     *
+     * @param load String of the input data.
+     */
+    virtual void LoadString(const std::string& load) = 0;
+
+    /**
+     * Returns a string representation of the data. If the data is an enum, it returns a string of
+     * the enum value. If the internal data type is not an enum, this is equivalent to ToString.
+     *
+     * e.g. renderer_backend.Canonicalize() == "OpenGL"
+     *
+     * @returns Canonicalized string representation of the internal data
+     */
+    [[nodiscard]] virtual std::string Canonicalize() const = 0;
+
+    /*
+     * Metadata
+     */
+
+    /**
+     * @returns A unique identifier for the Setting's internal data type.
+     */
+    [[nodiscard]] virtual std::type_index TypeId() const = 0;
+
+    /**
+     * Returns true if the Setting's internal data type is an enum.
+     *
+     * @returns True if the Setting's internal data type is an enum
+     */
+    [[nodiscard]] virtual constexpr bool IsEnum() const = 0;
+
+    /**
+     * Returns true if the current setting is Switchable.
+     *
+     * @returns If the setting is a SwitchableSetting
+     */
+    [[nodiscard]] virtual constexpr bool Switchable() const {
+        return false;
+    }
+
+    /**
+     * Returns true to suggest that a frontend can read or write the setting to a configuration
+     * file.
+     *
+     * @returns The save preference
+     */
+    [[nodiscard]] bool Save() const;
+
+    /**
+     * @returns true if the current setting can be changed while the guest is running.
+     */
+    [[nodiscard]] bool RuntimeModfiable() const;
+
+    /**
+     * @returns A unique number corresponding to the setting.
+     */
+    [[nodiscard]] constexpr u32 Id() const {
+        return id;
+    }
+
+    /**
+     * Returns the setting's category AKA INI group.
+     *
+     * @returns The setting's category
+     */
+    [[nodiscard]] Category GetCategory() const;
+
+    /**
+     * @returns Extra metadata for data representation in frontend implementations.
+     */
+    [[nodiscard]] u32 Specialization() const;
+
+    /**
+     * @returns Another BasicSetting if one is paired, or nullptr otherwise.
+     */
+    [[nodiscard]] BasicSetting* PairedSetting() const;
+
+    /**
+     * Returns the label this setting was created with.
+     *
+     * @returns A reference to the label
+     */
+    [[nodiscard]] const std::string& GetLabel() const;
+
+    /**
+     * @returns If the Setting checks input values for valid ranges.
+     */
+    [[nodiscard]] virtual constexpr bool Ranged() const = 0;
+
+    /**
+     * @returns The index of the enum if the underlying setting type is an enum, else max of u32.
+     */
+    [[nodiscard]] virtual constexpr u32 EnumIndex() const = 0;
+
+    /*
+     * Switchable settings
+     */
+
+    /**
+     * Sets a setting's global state. True means use the normal setting, false to use a custom
+     * value. Has no effect if the Setting is not Switchable.
+     *
+     * @param global The desired state
+     */
+    virtual void SetGlobal(bool global);
+
+    /**
+     * Returns true if the setting is using the normal setting value. Always true if the setting is
+     * not Switchable.
+     *
+     * @returns The Setting's global state
+     */
+    [[nodiscard]] virtual bool UsingGlobal() const;
+
+private:
+    const std::string label; ///< The setting's label
+    const Category category; ///< The setting's category AKA INI group
+    const u32 id;            ///< Unique integer for the setting
+    const bool save; ///< Suggests if the setting should be saved and read to a frontend config
+    const bool
+        runtime_modifiable;   ///< Suggests if the setting can be modified while a guest is running
+    const u32 specialization; ///< Extra data to identify representation of a setting
+    BasicSetting* const other_setting; ///< A paired setting
+};
+
+} // namespace Settings
diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h
new file mode 100644
index 0000000000..a1a29ebf63
--- /dev/null
+++ b/src/common/settings_enums.h
@@ -0,0 +1,214 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <string>
+#include <utility>
+#include <vector>
+#include "common/common_types.h"
+
+namespace Settings {
+
+template <typename T>
+struct EnumMetadata {
+    static constexpr std::vector<std::pair<std::string, T>> Canonicalizations();
+    static constexpr u32 Index();
+};
+
+#define PAIR_45(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_46(N, __VA_ARGS__))
+#define PAIR_44(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_45(N, __VA_ARGS__))
+#define PAIR_43(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_44(N, __VA_ARGS__))
+#define PAIR_42(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_43(N, __VA_ARGS__))
+#define PAIR_41(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_42(N, __VA_ARGS__))
+#define PAIR_40(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_41(N, __VA_ARGS__))
+#define PAIR_39(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_40(N, __VA_ARGS__))
+#define PAIR_38(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_39(N, __VA_ARGS__))
+#define PAIR_37(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_38(N, __VA_ARGS__))
+#define PAIR_36(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_37(N, __VA_ARGS__))
+#define PAIR_35(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_36(N, __VA_ARGS__))
+#define PAIR_34(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_35(N, __VA_ARGS__))
+#define PAIR_33(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_34(N, __VA_ARGS__))
+#define PAIR_32(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_33(N, __VA_ARGS__))
+#define PAIR_31(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_32(N, __VA_ARGS__))
+#define PAIR_30(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_31(N, __VA_ARGS__))
+#define PAIR_29(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_30(N, __VA_ARGS__))
+#define PAIR_28(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_29(N, __VA_ARGS__))
+#define PAIR_27(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_28(N, __VA_ARGS__))
+#define PAIR_26(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_27(N, __VA_ARGS__))
+#define PAIR_25(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_26(N, __VA_ARGS__))
+#define PAIR_24(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_25(N, __VA_ARGS__))
+#define PAIR_23(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_24(N, __VA_ARGS__))
+#define PAIR_22(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_23(N, __VA_ARGS__))
+#define PAIR_21(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_22(N, __VA_ARGS__))
+#define PAIR_20(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_21(N, __VA_ARGS__))
+#define PAIR_19(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_20(N, __VA_ARGS__))
+#define PAIR_18(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_19(N, __VA_ARGS__))
+#define PAIR_17(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_18(N, __VA_ARGS__))
+#define PAIR_16(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_17(N, __VA_ARGS__))
+#define PAIR_15(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_16(N, __VA_ARGS__))
+#define PAIR_14(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_15(N, __VA_ARGS__))
+#define PAIR_13(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_14(N, __VA_ARGS__))
+#define PAIR_12(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_13(N, __VA_ARGS__))
+#define PAIR_11(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_12(N, __VA_ARGS__))
+#define PAIR_10(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_11(N, __VA_ARGS__))
+#define PAIR_9(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_10(N, __VA_ARGS__))
+#define PAIR_8(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_9(N, __VA_ARGS__))
+#define PAIR_7(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_8(N, __VA_ARGS__))
+#define PAIR_6(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_7(N, __VA_ARGS__))
+#define PAIR_5(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_6(N, __VA_ARGS__))
+#define PAIR_4(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_5(N, __VA_ARGS__))
+#define PAIR_3(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_4(N, __VA_ARGS__))
+#define PAIR_2(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_3(N, __VA_ARGS__))
+#define PAIR_1(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_2(N, __VA_ARGS__))
+#define PAIR(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_1(N, __VA_ARGS__))
+
+#define ENUM(NAME, ...)                                                                            \
+    enum class NAME : u32 { __VA_ARGS__ };                                                         \
+    template <>                                                                                    \
+    constexpr std::vector<std::pair<std::string, NAME>> EnumMetadata<NAME>::Canonicalizations() {  \
+        return {PAIR(NAME, __VA_ARGS__)};                                                          \
+    }                                                                                              \
+    template <>                                                                                    \
+    constexpr u32 EnumMetadata<NAME>::Index() {                                                    \
+        return __COUNTER__;                                                                        \
+    }
+
+// AudioEngine must be specified discretely due to having existing but slightly different
+// canonicalizations
+// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
+enum class AudioEngine : u32 {
+    Auto,
+    Cubeb,
+    Sdl2,
+    Null,
+};
+
+template <>
+constexpr std::vector<std::pair<std::string, AudioEngine>>
+EnumMetadata<AudioEngine>::Canonicalizations() {
+    return {
+        {"auto", AudioEngine::Auto},
+        {"cubeb", AudioEngine::Cubeb},
+        {"sdl2", AudioEngine::Sdl2},
+        {"null", AudioEngine::Null},
+    };
+}
+
+template <>
+constexpr u32 EnumMetadata<AudioEngine>::Index() {
+    // This is just a sufficiently large number that is more than the number of other enums declared
+    // here
+    return 100;
+}
+
+ENUM(AudioMode, Mono, Stereo, Surround);
+
+ENUM(Language, Japanese, EnglishAmerican, French, German, Italian, Spanish, Chinese, Korean, Dutch,
+     Portuguese, Russian, Taiwanese, EnglishBritish, FrenchCanadian, SpanishLatin,
+     ChineseSimplified, ChineseTraditional, PortugueseBrazilian);
+
+ENUM(Region, Japan, Usa, Europe, Australia, China, Korea, Taiwan);
+
+ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt, Gb, GbEire, Gmt,
+     GmtPlusZero, GmtMinusZero, GmtZero, Greenwich, Hongkong, Hst, Iceland, Iran, Israel, Jamaica,
+     Japan, Kwajalein, Libya, Met, Mst, Mst7Mdt, Navajo, Nz, NzChat, Poland, Portugal, Prc, Pst8Pdt,
+     Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu);
+
+ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16);
+
+ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
+
+ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
+
+ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
+
+ENUM(RendererBackend, OpenGL, Vulkan, Null);
+
+ENUM(ShaderBackend, Glsl, Glasm, SpirV);
+
+ENUM(GpuAccuracy, Normal, High, Extreme);
+
+ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
+
+ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb);
+
+ENUM(FullscreenMode, Borderless, Exclusive);
+
+ENUM(NvdecEmulation, Off, Cpu, Gpu);
+
+ENUM(ResolutionSetup, Res1_2X, Res3_4X, Res1X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X,
+     Res8X);
+
+ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, ScaleForce, Fsr, MaxEnum);
+
+ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
+
+ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
+
+template <typename Type>
+constexpr std::string CanonicalizeEnum(Type id) {
+    const auto group = EnumMetadata<Type>::Canonicalizations();
+    for (auto& [name, value] : group) {
+        if (value == id) {
+            return name;
+        }
+    }
+    return "unknown";
+}
+
+template <typename Type>
+constexpr Type ToEnum(const std::string& canonicalization) {
+    const auto group = EnumMetadata<Type>::Canonicalizations();
+    for (auto& [name, value] : group) {
+        if (name == canonicalization) {
+            return value;
+        }
+    }
+    return {};
+}
+} // namespace Settings
+
+#undef ENUM
+#undef PAIR
+#undef PAIR_1
+#undef PAIR_2
+#undef PAIR_3
+#undef PAIR_4
+#undef PAIR_5
+#undef PAIR_6
+#undef PAIR_7
+#undef PAIR_8
+#undef PAIR_9
+#undef PAIR_10
+#undef PAIR_12
+#undef PAIR_13
+#undef PAIR_14
+#undef PAIR_15
+#undef PAIR_16
+#undef PAIR_17
+#undef PAIR_18
+#undef PAIR_19
+#undef PAIR_20
+#undef PAIR_22
+#undef PAIR_23
+#undef PAIR_24
+#undef PAIR_25
+#undef PAIR_26
+#undef PAIR_27
+#undef PAIR_28
+#undef PAIR_29
+#undef PAIR_30
+#undef PAIR_32
+#undef PAIR_33
+#undef PAIR_34
+#undef PAIR_35
+#undef PAIR_36
+#undef PAIR_37
+#undef PAIR_38
+#undef PAIR_39
+#undef PAIR_40
+#undef PAIR_42
+#undef PAIR_43
+#undef PAIR_44
+#undef PAIR_45
diff --git a/src/common/settings_setting.h b/src/common/settings_setting.h
new file mode 100644
index 0000000000..a8beb06e9d
--- /dev/null
+++ b/src/common/settings_setting.h
@@ -0,0 +1,394 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <limits>
+#include <map>
+#include <optional>
+#include <stdexcept>
+#include <string>
+#include <typeindex>
+#include <typeinfo>
+#include "common/common_types.h"
+#include "common/settings_common.h"
+#include "common/settings_enums.h"
+
+namespace Settings {
+
+/** The Setting class is a simple resource manager. It defines a label and default value
+ * alongside the actual value of the setting for simpler and less-error prone use with frontend
+ * configurations. Specifying a default value and label is required. A minimum and maximum range
+ * can be specified for sanitization.
+ */
+template <typename Type, bool ranged = false>
+class Setting : public BasicSetting {
+protected:
+    Setting() = default;
+
+public:
+    /**
+     * Sets a default value, label, and setting value.
+     *
+     * @param linkage Setting registry
+     * @param default_val Initial value of the setting, and default value of the setting
+     * @param name Label for the setting
+     * @param category_ Category of the setting AKA INI group
+     * @param specialization_ Suggestion for how frontend implementations represent this in a config
+     * @param save_ Suggests that this should or should not be saved to a frontend config file
+     * @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
+     * @param other_setting_ A second Setting to associate to this one in metadata
+     */
+    explicit Setting(Linkage& linkage, const Type& default_val, const std::string& name,
+                     Category category_, u32 specialization_ = Specialization::Default,
+                     bool save_ = true, bool runtime_modifiable_ = false,
+                     BasicSetting* other_setting_ = nullptr)
+        requires(!ranged)
+        : BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_,
+                       other_setting_),
+          value{default_val}, default_value{default_val} {}
+    virtual ~Setting() = default;
+
+    /**
+     * Sets a default value, minimum value, maximum value, and label.
+     *
+     * @param linkage Setting registry
+     * @param default_val Initial value of the setting, and default value of the setting
+     * @param min_val Sets the minimum allowed value of the setting
+     * @param max_val Sets the maximum allowed value of the setting
+     * @param name Label for the setting
+     * @param category_ Category of the setting AKA INI group
+     * @param specialization_ Suggestion for how frontend implementations represent this in a config
+     * @param save_ Suggests that this should or should not be saved to a frontend config file
+     * @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
+     * @param other_setting_ A second Setting to associate to this one in metadata
+     */
+    explicit Setting(Linkage& linkage, const Type& default_val, const Type& min_val,
+                     const Type& max_val, const std::string& name, Category category_,
+                     u32 specialization_ = Specialization::Default, bool save_ = true,
+                     bool runtime_modifiable_ = false, BasicSetting* other_setting_ = nullptr)
+        requires(ranged)
+        : BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_,
+                       other_setting_),
+          value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val} {}
+
+    /**
+     *  Returns a reference to the setting's value.
+     *
+     * @returns A reference to the setting
+     */
+    [[nodiscard]] virtual const Type& GetValue() const {
+        return value;
+    }
+
+    /**
+     * Sets the setting to the given value.
+     *
+     * @param val The desired value
+     */
+    virtual void SetValue(const Type& val) {
+        Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
+        std::swap(value, temp);
+    }
+
+    /**
+     * Returns the value that this setting was created with.
+     *
+     * @returns A reference to the default value
+     */
+    [[nodiscard]] const Type& GetDefault() const {
+        return default_value;
+    }
+
+    [[nodiscard]] constexpr bool IsEnum() const override {
+        return std::is_enum_v<Type>;
+    }
+
+protected:
+    [[nodiscard]] std::string ToString(const Type& value_) const {
+        if constexpr (std::is_same_v<Type, std::string>) {
+            return value_;
+        } else if constexpr (std::is_same_v<Type, std::optional<u32>>) {
+            return value_.has_value() ? std::to_string(*value_) : "none";
+        } else if constexpr (std::is_same_v<Type, bool>) {
+            return value_ ? "true" : "false";
+        } else if constexpr (std::is_same_v<Type, AudioEngine>) {
+            // Compatibility with old AudioEngine setting being a string
+            return CanonicalizeEnum(value_);
+        } else {
+            return std::to_string(static_cast<u64>(value_));
+        }
+    }
+
+public:
+    /**
+     * Converts the value of the setting to a std::string. Respects the global state if the setting
+     * has one.
+     *
+     * @returns The current setting as a std::string
+     */
+    [[nodiscard]] std::string ToString() const override {
+        return ToString(this->GetValue());
+    }
+
+    /**
+     * Returns the default value of the setting as a std::string.
+     *
+     * @returns The default value as a string.
+     */
+    [[nodiscard]] std::string DefaultToString() const override {
+        return ToString(default_value);
+    }
+
+    /**
+     * Assigns a value to the setting.
+     *
+     * @param val The desired setting value
+     *
+     * @returns A reference to the setting
+     */
+    virtual const Type& operator=(const Type& val) {
+        Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
+        std::swap(value, temp);
+        return value;
+    }
+
+    /**
+     * Returns a reference to the setting.
+     *
+     * @returns A reference to the setting
+     */
+    explicit virtual operator const Type&() const {
+        return value;
+    }
+
+    /**
+     * Converts the given value to the Setting's type of value. Uses SetValue to enter the setting,
+     * thus respecting its constraints.
+     *
+     * @param input The desired value
+     */
+    void LoadString(const std::string& input) override final {
+        if (input.empty()) {
+            this->SetValue(this->GetDefault());
+            return;
+        }
+        try {
+            if constexpr (std::is_same_v<Type, std::string>) {
+                this->SetValue(input);
+            } else if constexpr (std::is_same_v<Type, std::optional<u32>>) {
+                this->SetValue(static_cast<u32>(std::stoul(input)));
+            } else if constexpr (std::is_same_v<Type, bool>) {
+                this->SetValue(input == "true");
+            } else if constexpr (std::is_same_v<Type, AudioEngine>) {
+                this->SetValue(ToEnum<Type>(input));
+            } else {
+                this->SetValue(static_cast<Type>(std::stoll(input)));
+            }
+        } catch (std::invalid_argument&) {
+            this->SetValue(this->GetDefault());
+        }
+    }
+
+    [[nodiscard]] std::string constexpr Canonicalize() const override final {
+        if constexpr (std::is_enum_v<Type>) {
+            return CanonicalizeEnum(this->GetValue());
+        } else {
+            return ToString(this->GetValue());
+        }
+    }
+
+    /**
+     * Gives us another way to identify the setting without having to go through a string.
+     *
+     * @returns the type_index of the setting's type
+     */
+    [[nodiscard]] std::type_index TypeId() const override final {
+        return std::type_index(typeid(Type));
+    }
+
+    [[nodiscard]] constexpr u32 EnumIndex() const override final {
+        if constexpr (std::is_enum_v<Type>) {
+            return EnumMetadata<Type>::Index();
+        } else {
+            return std::numeric_limits<u32>::max();
+        }
+    }
+
+    [[nodiscard]] std::string MinVal() const override final {
+        return this->ToString(minimum);
+    }
+    [[nodiscard]] std::string MaxVal() const override final {
+        return this->ToString(maximum);
+    }
+
+    [[nodiscard]] constexpr bool Ranged() const override {
+        return ranged;
+    }
+
+protected:
+    Type value{};               ///< The setting
+    const Type default_value{}; ///< The default value
+    const Type maximum{};       ///< Maximum allowed value of the setting
+    const Type minimum{};       ///< Minimum allowed value of the setting
+};
+
+/**
+ * The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
+ * custom setting to switch to when a guest application specifically requires it. The effect is that
+ * other components of the emulator can access the setting's intended value without any need for the
+ * component to ask whether the custom or global setting is needed at the moment.
+ *
+ * By default, the global setting is used.
+ */
+template <typename Type, bool ranged = false>
+class SwitchableSetting : virtual public Setting<Type, ranged> {
+public:
+    /**
+     * Sets a default value, label, and setting value.
+     *
+     * @param linkage Setting registry
+     * @param default_val Initial value of the setting, and default value of the setting
+     * @param name Label for the setting
+     * @param category_ Category of the setting AKA INI group
+     * @param specialization_ Suggestion for how frontend implementations represent this in a config
+     * @param save_ Suggests that this should or should not be saved to a frontend config file
+     * @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
+     * @param other_setting_ A second Setting to associate to this one in metadata
+     */
+    explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
+                               Category category_, u32 specialization_ = Specialization::Default,
+                               bool save_ = true, bool runtime_modifiable_ = false,
+                               BasicSetting* other_setting_ = nullptr)
+        requires(!ranged)
+        : Setting<Type, false>{
+              linkage, default_val,         name,          category_, specialization_,
+              save_,   runtime_modifiable_, other_setting_} {
+        linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
+    }
+    virtual ~SwitchableSetting() = default;
+
+    /**
+     * Sets a default value, minimum value, maximum value, and label.
+     *
+     * @param linkage Setting registry
+     * @param default_val Initial value of the setting, and default value of the setting
+     * @param min_val Sets the minimum allowed value of the setting
+     * @param max_val Sets the maximum allowed value of the setting
+     * @param name Label for the setting
+     * @param category_ Category of the setting AKA INI group
+     * @param specialization_ Suggestion for how frontend implementations represent this in a config
+     * @param save_ Suggests that this should or should not be saved to a frontend config file
+     * @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
+     * @param other_setting_ A second Setting to associate to this one in metadata
+     */
+    explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
+                               const Type& max_val, const std::string& name, Category category_,
+                               u32 specialization_ = Specialization::Default, bool save_ = true,
+                               bool runtime_modifiable_ = false,
+                               BasicSetting* other_setting_ = nullptr)
+        requires(ranged)
+        : Setting<Type, true>{linkage,         default_val, min_val,
+                              max_val,         name,        category_,
+                              specialization_, save_,       runtime_modifiable_,
+                              other_setting_} {
+        linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
+    }
+
+    /**
+     * Tells this setting to represent either the global or custom setting when other member
+     * functions are used.
+     *
+     * @param to_global Whether to use the global or custom setting.
+     */
+    void SetGlobal(bool to_global) override final {
+        use_global = to_global;
+    }
+
+    /**
+     * Returns whether this setting is using the global setting or not.
+     *
+     * @returns The global state
+     */
+    [[nodiscard]] bool UsingGlobal() const override final {
+        return use_global;
+    }
+
+    /**
+     * Returns either the global or custom setting depending on the values of this setting's global
+     * state or if the global value was specifically requested.
+     *
+     * @param need_global Request global value regardless of setting's state; defaults to false
+     *
+     * @returns The required value of the setting
+     */
+    [[nodiscard]] const Type& GetValue() const override final {
+        if (use_global) {
+            return this->value;
+        }
+        return custom;
+    }
+    [[nodiscard]] const Type& GetValue(bool need_global) const {
+        if (use_global || need_global) {
+            return this->value;
+        }
+        return custom;
+    }
+
+    /**
+     * Sets the current setting value depending on the global state.
+     *
+     * @param val The new value
+     */
+    void SetValue(const Type& val) override final {
+        Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
+        if (use_global) {
+            std::swap(this->value, temp);
+        } else {
+            std::swap(custom, temp);
+        }
+    }
+
+    [[nodiscard]] constexpr bool Switchable() const override final {
+        return true;
+    }
+
+    [[nodiscard]] std::string ToStringGlobal() const override final {
+        return this->ToString(this->value);
+    }
+
+    /**
+     * Assigns the current setting value depending on the global state.
+     *
+     * @param val The new value
+     *
+     * @returns A reference to the current setting value
+     */
+    const Type& operator=(const Type& val) override final {
+        Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
+        if (use_global) {
+            std::swap(this->value, temp);
+            return this->value;
+        }
+        std::swap(custom, temp);
+        return custom;
+    }
+
+    /**
+     * Returns the current setting value depending on the global state.
+     *
+     * @returns A reference to the current setting value
+     */
+    explicit operator const Type&() const override final {
+        if (use_global) {
+            return this->value;
+        }
+        return custom;
+    }
+
+protected:
+    bool use_global{true}; ///< The setting's global state
+    Type custom{};         ///< The custom value of the setting
+};
+
+} // namespace Settings
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index c97158a713..44a297cdcb 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -287,7 +287,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
         }
     } else {
         // Unsafe optimizations
-        if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
+        if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) {
             config.unsafe_optimizations = true;
             if (Settings::values.cpuopt_unsafe_unfuse_fma) {
                 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
@@ -307,7 +307,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
         }
 
         // Curated optimizations
-        if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
+        if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) {
             config.unsafe_optimizations = true;
             config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
             config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
@@ -316,7 +316,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
         }
 
         // Paranoia mode for debugging optimizations
-        if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Paranoid) {
+        if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Paranoid) {
             config.unsafe_optimizations = false;
             config.optimizations = Dynarmic::no_optimizations;
         }
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 791d466ca3..2e3674b6d8 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -347,7 +347,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
         }
     } else {
         // Unsafe optimizations
-        if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
+        if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) {
             config.unsafe_optimizations = true;
             if (Settings::values.cpuopt_unsafe_unfuse_fma) {
                 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
@@ -367,7 +367,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
         }
 
         // Curated optimizations
-        if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
+        if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) {
             config.unsafe_optimizations = true;
             config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
             config.fastmem_address_space_bits = 64;
@@ -375,7 +375,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
         }
 
         // Paranoia mode for debugging optimizations
-        if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Paranoid) {
+        if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Paranoid) {
             config.unsafe_optimizations = false;
             config.optimizations = Dynarmic::no_optimizations;
         }
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 48233d7c82..2f67e60a97 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -12,6 +12,7 @@
 #include "common/logging/log.h"
 #include "common/microprofile.h"
 #include "common/settings.h"
+#include "common/settings_enums.h"
 #include "common/string_util.h"
 #include "core/arm/exclusive_monitor.h"
 #include "core/core.h"
@@ -140,16 +141,13 @@ struct System::Impl {
         device_memory = std::make_unique<Core::DeviceMemory>();
 
         is_multicore = Settings::values.use_multi_core.GetValue();
-        extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
+        extended_memory_layout =
+            Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb;
 
         core_timing.SetMulticore(is_multicore);
         core_timing.Initialize([&system]() { system.RegisterHostThread(); });
 
-        const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
-        const auto current_time =
-            std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
-        Settings::values.custom_rtc_differential =
-            Settings::values.custom_rtc.value_or(current_time) - current_time;
+        RefreshTime();
 
         // Create a default fs if one doesn't already exist.
         if (virtual_filesystem == nullptr) {
@@ -172,7 +170,8 @@ struct System::Impl {
     void ReinitializeIfNecessary(System& system) {
         const bool must_reinitialize =
             is_multicore != Settings::values.use_multi_core.GetValue() ||
-            extended_memory_layout != Settings::values.use_unsafe_extended_memory_layout.GetValue();
+            extended_memory_layout != (Settings::values.memory_layout_mode.GetValue() !=
+                                       Settings::MemoryLayout::Memory_4Gb);
 
         if (!must_reinitialize) {
             return;
@@ -181,11 +180,22 @@ struct System::Impl {
         LOG_DEBUG(Kernel, "Re-initializing");
 
         is_multicore = Settings::values.use_multi_core.GetValue();
-        extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
+        extended_memory_layout =
+            Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb;
 
         Initialize(system);
     }
 
+    void RefreshTime() {
+        const auto posix_time = std::chrono::system_clock::now().time_since_epoch();
+        const auto current_time =
+            std::chrono::duration_cast<std::chrono::seconds>(posix_time).count();
+        Settings::values.custom_rtc_differential =
+            (Settings::values.custom_rtc_enabled ? Settings::values.custom_rtc.GetValue()
+                                                 : current_time) -
+            current_time;
+    }
+
     void Run() {
         std::unique_lock<std::mutex> lk(suspend_guard);
 
@@ -1028,6 +1038,8 @@ void System::Exit() {
 }
 
 void System::ApplySettings() {
+    impl->RefreshTime();
+
     if (IsPoweredOn()) {
         Renderer().RefreshBaseSettings();
     }
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index cd9ac2e751..0697c29aec 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -68,7 +68,8 @@ NACP::NACP(VirtualFile file) {
 NACP::~NACP() = default;
 
 const LanguageEntry& NACP::GetLanguageEntry() const {
-    Language language = language_to_codes[Settings::values.language_index.GetValue()];
+    Language language =
+        language_to_codes[static_cast<s32>(Settings::values.language_index.GetValue())];
 
     {
         const auto& language_entry = raw.language_entries.at(static_cast<u8>(language));
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index d3286b3520..2ba1b34a40 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -626,8 +626,8 @@ PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const {
     auto nacp = nacp_file == nullptr ? nullptr : std::make_unique<NACP>(nacp_file);
 
     // Get language code from settings
-    const auto language_code =
-        Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index.GetValue());
+    const auto language_code = Service::Set::GetLanguageCodeFromIndex(
+        static_cast<u32>(Settings::values.language_index.GetValue()));
 
     // Convert to application language and get priority list
     const auto application_language =
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
index 49bdc671ee..4cfdf45588 100644
--- a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
+++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
@@ -35,13 +35,27 @@ namespace {
 using namespace Common::Literals;
 
 u32 GetMemorySizeForInit() {
-    return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemorySize_8GB
-                                                              : Smc::MemorySize_4GB;
+    switch (Settings::values.memory_layout_mode.GetValue()) {
+    case Settings::MemoryLayout::Memory_4Gb:
+        return Smc::MemorySize_4GB;
+    case Settings::MemoryLayout::Memory_6Gb:
+        return Smc::MemorySize_6GB;
+    case Settings::MemoryLayout::Memory_8Gb:
+        return Smc::MemorySize_8GB;
+    }
+    return Smc::MemorySize_4GB;
 }
 
 Smc::MemoryArrangement GetMemoryArrangeForInit() {
-    return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemoryArrangement_8GB
-                                                              : Smc::MemoryArrangement_4GB;
+    switch (Settings::values.memory_layout_mode.GetValue()) {
+    case Settings::MemoryLayout::Memory_4Gb:
+        return Smc::MemoryArrangement_4GB;
+    case Settings::MemoryLayout::Memory_6Gb:
+        return Smc::MemoryArrangement_6GB;
+    case Settings::MemoryLayout::Memory_8Gb:
+        return Smc::MemoryArrangement_8GB;
+    }
+    return Smc::MemoryArrangement_4GB;
 }
 } // namespace
 
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 44c7cb22f2..e573e2a57d 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -81,7 +81,8 @@ Result KProcess::Initialize(KProcess* process, Core::System& system, std::string
     process->m_capabilities.InitializeForMetadatalessProcess();
     process->m_is_initialized = true;
 
-    std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
+    std::mt19937 rng(Settings::values.rng_seed_enabled ? Settings::values.rng_seed.GetValue()
+                                                       : static_cast<u32>(std::time(nullptr)));
     std::uniform_int_distribution<u64> distribution;
     std::generate(process->m_random_entropy.begin(), process->m_random_entropy.end(),
                   [&] { return distribution(rng); });
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 376067a950..91c5a21827 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -409,7 +409,7 @@ ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
 
     // Get language code from settings
     const auto language_code =
-        Set::GetLanguageCodeFromIndex(Settings::values.language_index.GetValue());
+        Set::GetLanguageCodeFromIndex(static_cast<s32>(Settings::values.language_index.GetValue()));
 
     // Convert to application language, get priority list
     const auto application_language = ConvertToApplicationLanguage(language_code);
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index f5788b4819..83f888c54f 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -93,7 +93,8 @@ void GetAvailableLanguageCodesImpl(HLERequestContext& ctx, std::size_t max_entri
 }
 
 void GetKeyCodeMapImpl(HLERequestContext& ctx) {
-    const auto language_code = available_language_codes[Settings::values.language_index.GetValue()];
+    const auto language_code =
+        available_language_codes[static_cast<s32>(Settings::values.language_index.GetValue())];
     const auto key_code =
         std::find_if(language_to_layout.cbegin(), language_to_layout.cend(),
                      [=](const auto& element) { return element.first == language_code; });
@@ -162,7 +163,7 @@ void SET::GetQuestFlag(HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(ResultSuccess);
-    rb.Push(static_cast<u32>(Settings::values.quest_flag.GetValue()));
+    rb.Push(static_cast<s32>(Settings::values.quest_flag.GetValue()));
 }
 
 void SET::GetLanguageCode(HLERequestContext& ctx) {
@@ -170,7 +171,8 @@ void SET::GetLanguageCode(HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 4};
     rb.Push(ResultSuccess);
-    rb.PushEnum(available_language_codes[Settings::values.language_index.GetValue()]);
+    rb.PushEnum(
+        available_language_codes[static_cast<s32>(Settings::values.language_index.GetValue())]);
 }
 
 void SET::GetRegionCode(HLERequestContext& ctx) {
@@ -178,7 +180,7 @@ void SET::GetRegionCode(HLERequestContext& ctx) {
 
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(ResultSuccess);
-    rb.Push(Settings::values.region_index.GetValue());
+    rb.Push(static_cast<u32>(Settings::values.region_index.GetValue()));
 }
 
 void SET::GetKeyCodeMap(HLERequestContext& ctx) {
diff --git a/src/core/hle/service/spl/spl_module.cpp b/src/core/hle/service/spl/spl_module.cpp
index 0227d43934..cd631b2eaf 100644
--- a/src/core/hle/service/spl/spl_module.cpp
+++ b/src/core/hle/service/spl/spl_module.cpp
@@ -19,7 +19,8 @@ namespace Service::SPL {
 Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
                              const char* name)
     : ServiceFramework{system_, name}, module{std::move(module_)},
-      rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))) {}
+      rng(Settings::values.rng_seed_enabled ? Settings::values.rng_seed.GetValue()
+                                            : static_cast<u32>(std::time(nullptr))) {}
 
 Module::Interface::~Interface() = default;
 
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp
index 3b6047ad09..1b96de37a2 100644
--- a/src/core/hle/service/time/time_zone_content_manager.cpp
+++ b/src/core/hle/service/time/time_zone_content_manager.cpp
@@ -78,7 +78,8 @@ TimeZoneContentManager::TimeZoneContentManager(Core::System& system_)
       location_name_cache{BuildLocationNameCache(time_zone_binary)} {}
 
 void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
-    const auto timezone_setting = Settings::GetTimeZoneString();
+    const auto timezone_setting =
+        Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue());
 
     if (FileSys::VirtualFile vfs_file;
         GetTimeZoneInfoFile(timezone_setting, vfs_file) == ResultSuccess) {
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 7a2f3c90af..62b3f66361 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -61,13 +61,13 @@ static const char* TranslateRenderer(Settings::RendererBackend backend) {
     return "Unknown";
 }
 
-static const char* TranslateGPUAccuracyLevel(Settings::GPUAccuracy backend) {
+static const char* TranslateGPUAccuracyLevel(Settings::GpuAccuracy backend) {
     switch (backend) {
-    case Settings::GPUAccuracy::Normal:
+    case Settings::GpuAccuracy::Normal:
         return "Normal";
-    case Settings::GPUAccuracy::High:
+    case Settings::GpuAccuracy::High:
         return "High";
-    case Settings::GPUAccuracy::Extreme:
+    case Settings::GpuAccuracy::Extreme:
         return "Extreme";
     }
     return "Unknown";
@@ -77,9 +77,9 @@ static const char* TranslateNvdecEmulation(Settings::NvdecEmulation backend) {
     switch (backend) {
     case Settings::NvdecEmulation::Off:
         return "Off";
-    case Settings::NvdecEmulation::CPU:
+    case Settings::NvdecEmulation::Cpu:
         return "CPU";
-    case Settings::NvdecEmulation::GPU:
+    case Settings::NvdecEmulation::Gpu:
         return "GPU";
     }
     return "Unknown";
@@ -91,14 +91,26 @@ static constexpr const char* TranslateVSyncMode(Settings::VSyncMode mode) {
         return "Immediate";
     case Settings::VSyncMode::Mailbox:
         return "Mailbox";
-    case Settings::VSyncMode::FIFO:
+    case Settings::VSyncMode::Fifo:
         return "FIFO";
-    case Settings::VSyncMode::FIFORelaxed:
+    case Settings::VSyncMode::FifoRelaxed:
         return "FIFO Relaxed";
     }
     return "Unknown";
 }
 
+static constexpr const char* TranslateASTCDecodeMode(Settings::AstcDecodeMode mode) {
+    switch (mode) {
+    case Settings::AstcDecodeMode::Cpu:
+        return "CPU";
+    case Settings::AstcDecodeMode::Gpu:
+        return "GPU";
+    case Settings::AstcDecodeMode::CpuAsynchronous:
+        return "CPU Asynchronous";
+    }
+    return "Unknown";
+}
+
 u64 GetTelemetryId() {
     u64 telemetry_id{};
     const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id";
@@ -240,7 +252,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
 
     // Log user configuration information
     constexpr auto field_type = Telemetry::FieldType::UserConfig;
-    AddField(field_type, "Audio_SinkId", Settings::values.sink_id.GetValue());
+    AddField(field_type, "Audio_SinkId",
+             Settings::CanonicalizeEnum(Settings::values.sink_id.GetValue()));
     AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
     AddField(field_type, "Renderer_Backend",
              TranslateRenderer(Settings::values.renderer_backend.GetValue()));
@@ -254,7 +267,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
              Settings::values.use_asynchronous_gpu_emulation.GetValue());
     AddField(field_type, "Renderer_NvdecEmulation",
              TranslateNvdecEmulation(Settings::values.nvdec_emulation.GetValue()));
-    AddField(field_type, "Renderer_AccelerateASTC", Settings::values.accelerate_astc.GetValue());
+    AddField(field_type, "Renderer_AccelerateASTC",
+             TranslateASTCDecodeMode(Settings::values.accelerate_astc.GetValue()));
     AddField(field_type, "Renderer_UseVsync",
              TranslateVSyncMode(Settings::values.vsync_mode.GetValue()));
     AddField(field_type, "Renderer_ShaderBackend",
diff --git a/src/video_core/host1x/codecs/codec.cpp b/src/video_core/host1x/codecs/codec.cpp
index da07a556f4..220cce28ab 100644
--- a/src/video_core/host1x/codecs/codec.cpp
+++ b/src/video_core/host1x/codecs/codec.cpp
@@ -247,7 +247,7 @@ void Codec::Initialize() {
     av_codec = avcodec_find_decoder(codec);
 
     InitializeAvCodecContext();
-    if (Settings::values.nvdec_emulation.GetValue() == Settings::NvdecEmulation::GPU) {
+    if (Settings::values.nvdec_emulation.GetValue() == Settings::NvdecEmulation::Gpu) {
         InitializeGpuDecoder();
     }
     if (const int res = avcodec_open2(av_codec_ctx, av_codec, nullptr); res < 0) {
diff --git a/src/video_core/host1x/codecs/h264.cpp b/src/video_core/host1x/codecs/h264.cpp
index 862904e397..ece79b1e25 100644
--- a/src/video_core/host1x/codecs/h264.cpp
+++ b/src/video_core/host1x/codecs/h264.cpp
@@ -84,7 +84,7 @@ std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters
 
     // TODO (ameerj): Where do we get this number, it seems to be particular for each stream
     const auto nvdec_decoding = Settings::values.nvdec_emulation.GetValue();
-    const bool uses_gpu_decoding = nvdec_decoding == Settings::NvdecEmulation::GPU;
+    const bool uses_gpu_decoding = nvdec_decoding == Settings::NvdecEmulation::Gpu;
     const u32 max_num_ref_frames = uses_gpu_decoding ? 6u : 16u;
     writer.WriteUe(max_num_ref_frames);
     writer.WriteBit(false);
diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp
index f9ca55c36d..d705018607 100644
--- a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp
+++ b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp
@@ -34,13 +34,13 @@ ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cac
     : texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
       program_manager{program_manager_}, info{info_} {
     switch (device.GetShaderBackend()) {
-    case Settings::ShaderBackend::GLSL:
+    case Settings::ShaderBackend::Glsl:
         source_program = CreateProgram(code, GL_COMPUTE_SHADER);
         break;
-    case Settings::ShaderBackend::GLASM:
+    case Settings::ShaderBackend::Glasm:
         assembly_program = CompileProgram(code, GL_COMPUTE_PROGRAM_NV);
         break;
-    case Settings::ShaderBackend::SPIRV:
+    case Settings::ShaderBackend::SpirV:
         source_program = CreateProgram(code_v, GL_COMPUTE_SHADER);
         break;
     }
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 33e63c17d7..ee140c9c21 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -177,15 +177,15 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
     has_fast_buffer_sub_data = is_nvidia && !disable_fast_buffer_sub_data;
 
     shader_backend = Settings::values.shader_backend.GetValue();
-    use_assembly_shaders = shader_backend == Settings::ShaderBackend::GLASM &&
+    use_assembly_shaders = shader_backend == Settings::ShaderBackend::Glasm &&
                            GLAD_GL_NV_gpu_program5 && GLAD_GL_NV_compute_program5 &&
                            GLAD_GL_NV_transform_feedback && GLAD_GL_NV_transform_feedback2;
-    if (shader_backend == Settings::ShaderBackend::GLASM && !use_assembly_shaders) {
+    if (shader_backend == Settings::ShaderBackend::Glasm && !use_assembly_shaders) {
         LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported");
-        shader_backend = Settings::ShaderBackend::GLSL;
+        shader_backend = Settings::ShaderBackend::Glsl;
     }
 
-    if (shader_backend == Settings::ShaderBackend::GLSL && is_nvidia) {
+    if (shader_backend == Settings::ShaderBackend::Glsl && is_nvidia) {
         const std::string_view driver_version = version.substr(13);
         const int version_major =
             std::atoi(driver_version.substr(0, driver_version.find(".")).data());
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
index 71f720c635..f822fa8565 100644
--- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
+++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
@@ -236,18 +236,18 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
                force_context_flush](ShaderContext::Context*) mutable {
         for (size_t stage = 0; stage < 5; ++stage) {
             switch (backend) {
-            case Settings::ShaderBackend::GLSL:
+            case Settings::ShaderBackend::Glsl:
                 if (!sources_[stage].empty()) {
                     source_programs[stage] = CreateProgram(sources_[stage], Stage(stage));
                 }
                 break;
-            case Settings::ShaderBackend::GLASM:
+            case Settings::ShaderBackend::Glasm:
                 if (!sources_[stage].empty()) {
                     assembly_programs[stage] =
                         CompileProgram(sources_[stage], AssemblyStage(stage));
                 }
                 break;
-            case Settings::ShaderBackend::SPIRV:
+            case Settings::ShaderBackend::SpirV:
                 if (!sources_spirv_[stage].empty()) {
                     source_programs[stage] = CreateProgram(sources_spirv_[stage], Stage(stage));
                 }
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 7e1d7f92e7..618cb63547 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -522,14 +522,14 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
         const auto runtime_info{
             MakeRuntimeInfo(key, program, previous_program, glasm_use_storage_buffers, use_glasm)};
         switch (device.GetShaderBackend()) {
-        case Settings::ShaderBackend::GLSL:
+        case Settings::ShaderBackend::Glsl:
             ConvertLegacyToGeneric(program, runtime_info);
             sources[stage_index] = EmitGLSL(profile, runtime_info, program, binding);
             break;
-        case Settings::ShaderBackend::GLASM:
+        case Settings::ShaderBackend::Glasm:
             sources[stage_index] = EmitGLASM(profile, runtime_info, program, binding);
             break;
-        case Settings::ShaderBackend::SPIRV:
+        case Settings::ShaderBackend::SpirV:
             ConvertLegacyToGeneric(program, runtime_info);
             sources_spirv[stage_index] = EmitSPIRV(profile, runtime_info, program, binding);
             break;
@@ -582,13 +582,13 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
     std::string code{};
     std::vector<u32> code_spirv;
     switch (device.GetShaderBackend()) {
-    case Settings::ShaderBackend::GLSL:
+    case Settings::ShaderBackend::Glsl:
         code = EmitGLSL(profile, program);
         break;
-    case Settings::ShaderBackend::GLASM:
+    case Settings::ShaderBackend::Glasm:
         code = EmitGLASM(profile, info, program);
         break;
-    case Settings::ShaderBackend::SPIRV:
+    case Settings::ShaderBackend::SpirV:
         code_spirv = EmitSPIRV(profile, program);
         break;
     }
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 3b446be074..9cafd2983b 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -232,10 +232,9 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4
 [[nodiscard]] bool CanBeAccelerated(const TextureCacheRuntime& runtime,
                                     const VideoCommon::ImageInfo& info) {
     if (IsPixelFormatASTC(info.format) && info.size.depth == 1 && !runtime.HasNativeASTC()) {
-        return Settings::values.accelerate_astc.GetValue() &&
+        return Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu &&
                Settings::values.astc_recompression.GetValue() ==
-                   Settings::AstcRecompression::Uncompressed &&
-               !Settings::values.async_astc.GetValue();
+                   Settings::AstcRecompression::Uncompressed;
     }
     // Disable other accelerated uploads for now as they don't implement swizzled uploads
     return false;
@@ -267,7 +266,8 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4
 [[nodiscard]] bool CanBeDecodedAsync(const TextureCacheRuntime& runtime,
                                      const VideoCommon::ImageInfo& info) {
     if (IsPixelFormatASTC(info.format) && !runtime.HasNativeASTC()) {
-        return Settings::values.async_astc.GetValue();
+        return Settings::values.accelerate_astc.GetValue() ==
+               Settings::AstcDecodeMode::CpuAsynchronous;
     }
     return false;
 }
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 2a74c1d05b..6b8d4e554d 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -473,7 +473,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
     glBindTextureUnit(0, screen_info.display_texture);
 
     auto anti_aliasing = Settings::values.anti_aliasing.GetValue();
-    if (anti_aliasing > Settings::AntiAliasing::LastAA) {
+    if (anti_aliasing >= Settings::AntiAliasing::MaxEnum) {
         LOG_ERROR(Render_OpenGL, "Invalid antialiasing option selected {}", anti_aliasing);
         anti_aliasing = Settings::AntiAliasing::None;
         Settings::values.anti_aliasing.SetValue(anti_aliasing);
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index d3cddac690..81ef98f61f 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -45,8 +45,8 @@ static VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox,
             return mode;
         }
         switch (mode) {
-        case Settings::VSyncMode::FIFO:
-        case Settings::VSyncMode::FIFORelaxed:
+        case Settings::VSyncMode::Fifo:
+        case Settings::VSyncMode::FifoRelaxed:
             if (has_mailbox) {
                 return Settings::VSyncMode::Mailbox;
             } else if (has_imm) {
@@ -59,8 +59,8 @@ static VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox,
     }();
     if ((setting == Settings::VSyncMode::Mailbox && !has_mailbox) ||
         (setting == Settings::VSyncMode::Immediate && !has_imm) ||
-        (setting == Settings::VSyncMode::FIFORelaxed && !has_fifo_relaxed)) {
-        setting = Settings::VSyncMode::FIFO;
+        (setting == Settings::VSyncMode::FifoRelaxed && !has_fifo_relaxed)) {
+        setting = Settings::VSyncMode::Fifo;
     }
 
     switch (setting) {
@@ -68,9 +68,9 @@ static VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox,
         return VK_PRESENT_MODE_IMMEDIATE_KHR;
     case Settings::VSyncMode::Mailbox:
         return VK_PRESENT_MODE_MAILBOX_KHR;
-    case Settings::VSyncMode::FIFO:
+    case Settings::VSyncMode::Fifo:
         return VK_PRESENT_MODE_FIFO_KHR;
-    case Settings::VSyncMode::FIFORelaxed:
+    case Settings::VSyncMode::FifoRelaxed:
         return VK_PRESENT_MODE_FIFO_RELAXED_KHR;
     default:
         return VK_PRESENT_MODE_FIFO_KHR;
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index bf6ad6c792..53d749bd40 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -817,7 +817,7 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
     : device{device_}, scheduler{scheduler_}, memory_allocator{memory_allocator_},
       staging_buffer_pool{staging_buffer_pool_}, blit_image_helper{blit_image_helper_},
       render_pass_cache{render_pass_cache_}, resolution{Settings::values.resolution_info} {
-    if (Settings::values.accelerate_astc) {
+    if (Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu) {
         astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
                                   compute_pass_descriptor_queue, memory_allocator);
     }
@@ -1301,12 +1301,19 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
                                                    runtime->ViewFormats(info.format))),
       aspect_mask(ImageAspectMask(info.format)) {
     if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
-        if (Settings::values.async_astc.GetValue()) {
+        switch (Settings::values.accelerate_astc.GetValue()) {
+        case Settings::AstcDecodeMode::Gpu:
+            if (Settings::values.astc_recompression.GetValue() ==
+                    Settings::AstcRecompression::Uncompressed &&
+                info.size.depth == 1) {
+                flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
+            }
+            break;
+        case Settings::AstcDecodeMode::CpuAsynchronous:
             flags |= VideoCommon::ImageFlagBits::AsynchronousDecode;
-        } else if (Settings::values.astc_recompression.GetValue() ==
-                       Settings::AstcRecompression::Uncompressed &&
-                   Settings::values.accelerate_astc.GetValue() && info.size.depth == 1) {
-            flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
+            break;
+        default:
+            break;
         }
         flags |= VideoCommon::ImageFlagBits::Converted;
         flags |= VideoCommon::ImageFlagBits::CostlyLoad;
diff --git a/src/video_core/textures/texture.cpp b/src/video_core/textures/texture.cpp
index d8b88d9bc2..39c08b5ae1 100644
--- a/src/video_core/textures/texture.cpp
+++ b/src/video_core/textures/texture.cpp
@@ -72,12 +72,12 @@ float TSCEntry::MaxAnisotropy() const noexcept {
     }
     const auto anisotropic_settings = Settings::values.max_anisotropy.GetValue();
     s32 added_anisotropic{};
-    if (anisotropic_settings == 0) {
+    if (anisotropic_settings == Settings::AnisotropyMode::Automatic) {
         added_anisotropic = Settings::values.resolution_info.up_scale >>
                             Settings::values.resolution_info.down_shift;
         added_anisotropic = std::max(added_anisotropic - 1, 0);
     } else {
-        added_anisotropic = Settings::values.max_anisotropy.GetValue() - 1U;
+        added_anisotropic = static_cast<u32>(Settings::values.max_anisotropy.GetValue()) - 1U;
     }
     return static_cast<float>(1U << (max_anisotropy + added_anisotropic));
 }
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index fe98e3605e..2e4da696c0 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -143,6 +143,10 @@ add_executable(yuzu
     configuration/configure_web.ui
     configuration/input_profiles.cpp
     configuration/input_profiles.h
+    configuration/shared_translation.cpp
+    configuration/shared_translation.h
+    configuration/shared_widget.cpp
+    configuration/shared_widget.h
     debugger/console.cpp
     debugger/console.h
     debugger/controller.cpp
@@ -231,6 +235,12 @@ if (WIN32 AND YUZU_CRASH_DUMPS)
     target_compile_definitions(yuzu PRIVATE -DYUZU_DBGHELP)
 endif()
 
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+    target_compile_definitions(yuzu PRIVATE
+        $<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,15>:CANNOT_EXPLICITLY_INSTANTIATE>
+    )
+endif()
+
 file(GLOB COMPAT_LIST
      ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc
      ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 195d3556c9..b2405f9b87 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -1,12 +1,14 @@
 // SPDX-FileCopyrightText: 2014 Citra Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
+#include <algorithm>
 #include <array>
 #include <QKeySequence>
 #include <QSettings>
 #include "common/fs/fs.h"
 #include "common/fs/path_util.h"
 #include "common/settings.h"
+#include "common/settings_common.h"
 #include "core/core.h"
 #include "core/hle/service/acc/profile_manager.h"
 #include "core/hle/service/hid/controllers/npad.h"
@@ -16,9 +18,8 @@
 
 namespace FS = Common::FS;
 
-Config::Config(const std::string& config_name, ConfigType config_type) : type(config_type) {
-    global = config_type == ConfigType::GlobalConfig;
-
+Config::Config(const std::string& config_name, ConfigType config_type)
+    : type(config_type), global{config_type == ConfigType::GlobalConfig} {
     Initialize(config_name);
 }
 
@@ -89,10 +90,10 @@ const std::map<bool, QString> Config::use_docked_mode_texts_map = {
     {false, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))},
 };
 
-const std::map<Settings::GPUAccuracy, QString> Config::gpu_accuracy_texts_map = {
-    {Settings::GPUAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))},
-    {Settings::GPUAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))},
-    {Settings::GPUAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))},
+const std::map<Settings::GpuAccuracy, QString> Config::gpu_accuracy_texts_map = {
+    {Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))},
+    {Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))},
+    {Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))},
 };
 
 const std::map<Settings::RendererBackend, QString> Config::renderer_backend_texts_map = {
@@ -102,9 +103,9 @@ const std::map<Settings::RendererBackend, QString> Config::renderer_backend_text
 };
 
 const std::map<Settings::ShaderBackend, QString> Config::shader_backend_texts_map = {
-    {Settings::ShaderBackend::GLSL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))},
-    {Settings::ShaderBackend::GLASM, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))},
-    {Settings::ShaderBackend::SPIRV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))},
+    {Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))},
+    {Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))},
+    {Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))},
 };
 
 // This shouldn't have anything except static initializers (no functions). So
@@ -171,66 +172,6 @@ bool Config::IsCustomConfig() {
     return type == ConfigType::PerGameConfig;
 }
 
-/* {Read,Write}BasicSetting and WriteGlobalSetting templates must be defined here before their
- * usages later in this file. This allows explicit definition of some types that don't work
- * nicely with the general version.
- */
-
-// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant, nor
-// can it implicitly convert a QVariant back to a {std::,Q}string
-template <>
-void Config::ReadBasicSetting(Settings::Setting<std::string>& setting) {
-    const QString name = QString::fromStdString(setting.GetLabel());
-    const auto default_value = QString::fromStdString(setting.GetDefault());
-    if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
-        setting.SetValue(default_value.toStdString());
-    } else {
-        setting.SetValue(qt_config->value(name, default_value).toString().toStdString());
-    }
-}
-
-template <typename Type, bool ranged>
-void Config::ReadBasicSetting(Settings::Setting<Type, ranged>& setting) {
-    const QString name = QString::fromStdString(setting.GetLabel());
-    const Type default_value = setting.GetDefault();
-    if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
-        setting.SetValue(default_value);
-    } else {
-        setting.SetValue(
-            static_cast<QVariant>(qt_config->value(name, default_value)).value<Type>());
-    }
-}
-
-// Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant
-template <>
-void Config::WriteBasicSetting(const Settings::Setting<std::string>& setting) {
-    const QString name = QString::fromStdString(setting.GetLabel());
-    const std::string& value = setting.GetValue();
-    qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
-    qt_config->setValue(name, QString::fromStdString(value));
-}
-
-template <typename Type, bool ranged>
-void Config::WriteBasicSetting(const Settings::Setting<Type, ranged>& setting) {
-    const QString name = QString::fromStdString(setting.GetLabel());
-    const Type value = setting.GetValue();
-    qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
-    qt_config->setValue(name, value);
-}
-
-template <typename Type, bool ranged>
-void Config::WriteGlobalSetting(const Settings::SwitchableSetting<Type, ranged>& setting) {
-    const QString name = QString::fromStdString(setting.GetLabel());
-    const Type& value = setting.GetValue(global);
-    if (!global) {
-        qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
-    }
-    if (global || !setting.UsingGlobal()) {
-        qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault());
-        qt_config->setValue(name, value);
-    }
-}
-
 void Config::ReadPlayerValue(std::size_t player_index) {
     const QString player_prefix = [this, player_index] {
         if (type == ConfigType::InputProfile) {
@@ -351,15 +292,9 @@ void Config::ReadPlayerValue(std::size_t player_index) {
             player_motions = default_param;
         }
     }
-
-    if (player_index == 0) {
-        ReadMousePanningValues();
-    }
 }
 
 void Config::ReadDebugValues() {
-    ReadBasicSetting(Settings::values.debug_pad_enabled);
-
     for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
         const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
         auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i];
@@ -393,14 +328,6 @@ void Config::ReadDebugValues() {
     }
 }
 
-void Config::ReadKeyboardValues() {
-    ReadBasicSetting(Settings::values.keyboard_enabled);
-}
-
-void Config::ReadMouseValues() {
-    ReadBasicSetting(Settings::values.mouse_enabled);
-}
-
 void Config::ReadTouchscreenValues() {
     Settings::values.touchscreen.enabled =
         ReadSetting(QStringLiteral("touchscreen_enabled"), true).toBool();
@@ -414,9 +341,6 @@ void Config::ReadTouchscreenValues() {
 }
 
 void Config::ReadHidbusValues() {
-    Settings::values.enable_ring_controller =
-        ReadSetting(QStringLiteral("enable_ring_controller"), true).toBool();
-
     const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
         0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
     auto& ringcon_analogs = Settings::values.ringcon_analogs;
@@ -430,20 +354,10 @@ void Config::ReadHidbusValues() {
     }
 }
 
-void Config::ReadIrCameraValues() {
-    ReadBasicSetting(Settings::values.enable_ir_sensor);
-    ReadBasicSetting(Settings::values.ir_sensor_device);
-}
-
 void Config::ReadAudioValues() {
     qt_config->beginGroup(QStringLiteral("Audio"));
 
-    if (global) {
-        ReadBasicSetting(Settings::values.sink_id);
-        ReadBasicSetting(Settings::values.audio_output_device_id);
-        ReadBasicSetting(Settings::values.audio_input_device_id);
-    }
-    ReadGlobalSetting(Settings::values.volume);
+    ReadCategory(Settings::Category::Audio);
 
     qt_config->endGroup();
 }
@@ -451,11 +365,12 @@ void Config::ReadAudioValues() {
 void Config::ReadControlValues() {
     qt_config->beginGroup(QStringLiteral("Controls"));
 
+    ReadCategory(Settings::Category::Controls);
+
     Settings::values.players.SetGlobal(!IsCustomConfig());
     for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
         ReadPlayerValue(p);
     }
-    ReadGlobalSetting(Settings::values.use_docked_mode);
 
     // Disable docked mode if handheld is selected
     const auto controller_type = Settings::values.players.GetValue()[0].controller_type;
@@ -464,50 +379,18 @@ void Config::ReadControlValues() {
         Settings::values.use_docked_mode.SetValue(false);
     }
 
-    ReadGlobalSetting(Settings::values.vibration_enabled);
-    ReadGlobalSetting(Settings::values.enable_accurate_vibrations);
-    ReadGlobalSetting(Settings::values.motion_enabled);
     if (IsCustomConfig()) {
         qt_config->endGroup();
         return;
     }
     ReadDebugValues();
-    ReadKeyboardValues();
-    ReadMouseValues();
     ReadTouchscreenValues();
-    ReadMousePanningValues();
     ReadMotionTouchValues();
     ReadHidbusValues();
-    ReadIrCameraValues();
-
-#ifdef _WIN32
-    ReadBasicSetting(Settings::values.enable_raw_input);
-#else
-    Settings::values.enable_raw_input = false;
-#endif
-    ReadBasicSetting(Settings::values.emulate_analog_keyboard);
-    ReadBasicSetting(Settings::values.enable_joycon_driver);
-    ReadBasicSetting(Settings::values.enable_procon_driver);
-    ReadBasicSetting(Settings::values.random_amiibo_id);
-
-    ReadBasicSetting(Settings::values.tas_enable);
-    ReadBasicSetting(Settings::values.tas_loop);
-    ReadBasicSetting(Settings::values.pause_tas_on_load);
-
-    ReadBasicSetting(Settings::values.controller_navigation);
 
     qt_config->endGroup();
 }
 
-void Config::ReadMousePanningValues() {
-    ReadBasicSetting(Settings::values.mouse_panning);
-    ReadBasicSetting(Settings::values.mouse_panning_x_sensitivity);
-    ReadBasicSetting(Settings::values.mouse_panning_y_sensitivity);
-    ReadBasicSetting(Settings::values.mouse_panning_deadzone_counterweight);
-    ReadBasicSetting(Settings::values.mouse_panning_decay_strength);
-    ReadBasicSetting(Settings::values.mouse_panning_min_decay);
-}
-
 void Config::ReadMotionTouchValues() {
     int num_touch_from_button_maps =
         qt_config->beginReadArray(QStringLiteral("touch_from_button_maps"));
@@ -541,19 +424,14 @@ void Config::ReadMotionTouchValues() {
     }
     qt_config->endArray();
 
-    ReadBasicSetting(Settings::values.touch_device);
-    ReadBasicSetting(Settings::values.touch_from_button_map_index);
     Settings::values.touch_from_button_map_index = std::clamp(
         Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
-    ReadBasicSetting(Settings::values.udp_input_servers);
-    ReadBasicSetting(Settings::values.enable_udp_controller);
 }
 
 void Config::ReadCoreValues() {
     qt_config->beginGroup(QStringLiteral("Core"));
 
-    ReadGlobalSetting(Settings::values.use_multi_core);
-    ReadGlobalSetting(Settings::values.use_unsafe_extended_memory_layout);
+    ReadCategory(Settings::Category::Core);
 
     qt_config->endGroup();
 }
@@ -561,7 +439,6 @@ void Config::ReadCoreValues() {
 void Config::ReadDataStorageValues() {
     qt_config->beginGroup(QStringLiteral("Data Storage"));
 
-    ReadBasicSetting(Settings::values.use_virtual_sd);
     FS::SetYuzuPath(
         FS::YuzuPath::NANDDir,
         qt_config
@@ -597,9 +474,7 @@ void Config::ReadDataStorageValues() {
                         .toString()
                         .toStdString());
 
-    ReadBasicSetting(Settings::values.gamecard_inserted);
-    ReadBasicSetting(Settings::values.gamecard_current_game);
-    ReadBasicSetting(Settings::values.gamecard_path);
+    ReadCategory(Settings::Category::DataStorage);
 
     qt_config->endGroup();
 }
@@ -611,29 +486,17 @@ void Config::ReadDebuggingValues() {
     Settings::values.record_frame_times =
         qt_config->value(QStringLiteral("record_frame_times"), false).toBool();
 
-    ReadBasicSetting(Settings::values.use_gdbstub);
-    ReadBasicSetting(Settings::values.gdbstub_port);
-    ReadBasicSetting(Settings::values.program_args);
-    ReadBasicSetting(Settings::values.dump_exefs);
-    ReadBasicSetting(Settings::values.dump_nso);
-    ReadBasicSetting(Settings::values.enable_fs_access_log);
-    ReadBasicSetting(Settings::values.reporting_services);
-    ReadBasicSetting(Settings::values.quest_flag);
-    ReadBasicSetting(Settings::values.disable_macro_jit);
-    ReadBasicSetting(Settings::values.disable_macro_hle);
-    ReadBasicSetting(Settings::values.extended_logging);
-    ReadBasicSetting(Settings::values.use_debug_asserts);
-    ReadBasicSetting(Settings::values.use_auto_stub);
-    ReadBasicSetting(Settings::values.enable_all_controllers);
-    ReadBasicSetting(Settings::values.create_crash_dumps);
-    ReadBasicSetting(Settings::values.perform_vulkan_check);
+    ReadCategory(Settings::Category::Debugging);
+    ReadCategory(Settings::Category::DebuggingGraphics);
 
     qt_config->endGroup();
 }
 
 void Config::ReadServiceValues() {
     qt_config->beginGroup(QStringLiteral("Services"));
-    ReadBasicSetting(Settings::values.network_interface);
+
+    ReadCategory(Settings::Category::Services);
+
     qt_config->endGroup();
 }
 
@@ -659,8 +522,7 @@ void Config::ReadDisabledAddOnValues() {
 void Config::ReadMiscellaneousValues() {
     qt_config->beginGroup(QStringLiteral("Miscellaneous"));
 
-    ReadBasicSetting(Settings::values.log_filter);
-    ReadBasicSetting(Settings::values.use_dev_keys);
+    ReadCategory(Settings::Category::Miscellaneous);
 
     qt_config->endGroup();
 }
@@ -710,36 +572,9 @@ void Config::ReadPathValues() {
 void Config::ReadCpuValues() {
     qt_config->beginGroup(QStringLiteral("Cpu"));
 
-    ReadBasicSetting(Settings::values.cpu_accuracy_first_time);
-    if (Settings::values.cpu_accuracy_first_time) {
-        Settings::values.cpu_accuracy.SetValue(Settings::values.cpu_accuracy.GetDefault());
-        Settings::values.cpu_accuracy_first_time.SetValue(false);
-    } else {
-        ReadGlobalSetting(Settings::values.cpu_accuracy);
-    }
-
-    ReadGlobalSetting(Settings::values.cpuopt_unsafe_unfuse_fma);
-    ReadGlobalSetting(Settings::values.cpuopt_unsafe_reduce_fp_error);
-    ReadGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
-    ReadGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan);
-    ReadGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check);
-    ReadGlobalSetting(Settings::values.cpuopt_unsafe_ignore_global_monitor);
-
-    if (global) {
-        ReadBasicSetting(Settings::values.cpu_debug_mode);
-        ReadBasicSetting(Settings::values.cpuopt_page_tables);
-        ReadBasicSetting(Settings::values.cpuopt_block_linking);
-        ReadBasicSetting(Settings::values.cpuopt_return_stack_buffer);
-        ReadBasicSetting(Settings::values.cpuopt_fast_dispatcher);
-        ReadBasicSetting(Settings::values.cpuopt_context_elimination);
-        ReadBasicSetting(Settings::values.cpuopt_const_prop);
-        ReadBasicSetting(Settings::values.cpuopt_misc_ir);
-        ReadBasicSetting(Settings::values.cpuopt_reduce_misalign_checks);
-        ReadBasicSetting(Settings::values.cpuopt_fastmem);
-        ReadBasicSetting(Settings::values.cpuopt_fastmem_exclusives);
-        ReadBasicSetting(Settings::values.cpuopt_recompile_exclusives);
-        ReadBasicSetting(Settings::values.cpuopt_ignore_memory_aborts);
-    }
+    ReadCategory(Settings::Category::Cpu);
+    ReadCategory(Settings::Category::CpuDebug);
+    ReadCategory(Settings::Category::CpuUnsafe);
 
     qt_config->endGroup();
 }
@@ -747,47 +582,9 @@ void Config::ReadCpuValues() {
 void Config::ReadRendererValues() {
     qt_config->beginGroup(QStringLiteral("Renderer"));
 
-    ReadGlobalSetting(Settings::values.renderer_backend);
-    ReadGlobalSetting(Settings::values.async_presentation);
-    ReadGlobalSetting(Settings::values.renderer_force_max_clock);
-    ReadGlobalSetting(Settings::values.vulkan_device);
-    ReadGlobalSetting(Settings::values.fullscreen_mode);
-    ReadGlobalSetting(Settings::values.aspect_ratio);
-    ReadGlobalSetting(Settings::values.resolution_setup);
-    ReadGlobalSetting(Settings::values.scaling_filter);
-    ReadGlobalSetting(Settings::values.fsr_sharpening_slider);
-    ReadGlobalSetting(Settings::values.anti_aliasing);
-    ReadGlobalSetting(Settings::values.max_anisotropy);
-    ReadGlobalSetting(Settings::values.speed_limit);
-    ReadGlobalSetting(Settings::values.use_disk_shader_cache);
-    ReadGlobalSetting(Settings::values.gpu_accuracy);
-    ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
-    ReadGlobalSetting(Settings::values.nvdec_emulation);
-    ReadGlobalSetting(Settings::values.accelerate_astc);
-    ReadGlobalSetting(Settings::values.async_astc);
-    ReadGlobalSetting(Settings::values.astc_recompression);
-    ReadGlobalSetting(Settings::values.use_reactive_flushing);
-    ReadGlobalSetting(Settings::values.shader_backend);
-    ReadGlobalSetting(Settings::values.use_asynchronous_shaders);
-    ReadGlobalSetting(Settings::values.use_fast_gpu_time);
-    ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);
-    ReadGlobalSetting(Settings::values.enable_compute_pipelines);
-    ReadGlobalSetting(Settings::values.use_video_framerate);
-    ReadGlobalSetting(Settings::values.barrier_feedback_loops);
-    ReadGlobalSetting(Settings::values.bg_red);
-    ReadGlobalSetting(Settings::values.bg_green);
-    ReadGlobalSetting(Settings::values.bg_blue);
-
-    if (global) {
-        Settings::values.vsync_mode.SetValue(static_cast<Settings::VSyncMode>(
-            ReadSetting(QString::fromStdString(Settings::values.vsync_mode.GetLabel()),
-                        static_cast<u32>(Settings::values.vsync_mode.GetDefault()))
-                .value<u32>()));
-        ReadBasicSetting(Settings::values.renderer_debug);
-        ReadBasicSetting(Settings::values.renderer_shader_feedback);
-        ReadBasicSetting(Settings::values.enable_nsight_aftermath);
-        ReadBasicSetting(Settings::values.disable_shader_loop_safety_checks);
-    }
+    ReadCategory(Settings::Category::Renderer);
+    ReadCategory(Settings::Category::RendererAdvanced);
+    ReadCategory(Settings::Category::RendererDebug);
 
     qt_config->endGroup();
 }
@@ -834,41 +631,8 @@ void Config::ReadShortcutValues() {
 void Config::ReadSystemValues() {
     qt_config->beginGroup(QStringLiteral("System"));
 
-    ReadGlobalSetting(Settings::values.language_index);
-
-    ReadGlobalSetting(Settings::values.region_index);
-
-    ReadGlobalSetting(Settings::values.time_zone_index);
-
-    bool rng_seed_enabled;
-    ReadSettingGlobal(rng_seed_enabled, QStringLiteral("rng_seed_enabled"), false);
-    bool rng_seed_global =
-        global || qt_config->value(QStringLiteral("rng_seed/use_global"), true).toBool();
-    Settings::values.rng_seed.SetGlobal(rng_seed_global);
-    if (global || !rng_seed_global) {
-        if (rng_seed_enabled) {
-            Settings::values.rng_seed.SetValue(ReadSetting(QStringLiteral("rng_seed"), 0).toUInt());
-        } else {
-            Settings::values.rng_seed.SetValue(std::nullopt);
-        }
-    }
-
-    if (global) {
-        ReadBasicSetting(Settings::values.current_user);
-        Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0,
-                                                        Service::Account::MAX_USERS - 1);
-
-        const auto custom_rtc_enabled =
-            ReadSetting(QStringLiteral("custom_rtc_enabled"), false).toBool();
-        if (custom_rtc_enabled) {
-            Settings::values.custom_rtc = ReadSetting(QStringLiteral("custom_rtc"), 0).toLongLong();
-        } else {
-            Settings::values.custom_rtc = std::nullopt;
-        }
-        ReadBasicSetting(Settings::values.device_name);
-    }
-
-    ReadGlobalSetting(Settings::values.sound_index);
+    ReadCategory(Settings::Category::System);
+    ReadCategory(Settings::Category::SystemAudio);
 
     qt_config->endGroup();
 }
@@ -881,8 +645,6 @@ void Config::ReadUIValues() {
             QStringLiteral("theme"),
             QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second))
             .toString();
-    ReadBasicSetting(UISettings::values.enable_discord_presence);
-    ReadBasicSetting(UISettings::values.select_user_on_boot);
 
     ReadUIGamelistValues();
     ReadUILayoutValues();
@@ -891,20 +653,8 @@ void Config::ReadUIValues() {
     ReadShortcutValues();
     ReadMultiplayerValues();
 
-    ReadBasicSetting(UISettings::values.single_window_mode);
-    ReadBasicSetting(UISettings::values.fullscreen);
-    ReadBasicSetting(UISettings::values.display_titlebar);
-    ReadBasicSetting(UISettings::values.show_filter_bar);
-    ReadBasicSetting(UISettings::values.show_status_bar);
-    ReadBasicSetting(UISettings::values.confirm_before_closing);
-    ReadBasicSetting(UISettings::values.first_start);
-    ReadBasicSetting(UISettings::values.callout_flags);
-    ReadBasicSetting(UISettings::values.show_console);
-    ReadBasicSetting(UISettings::values.pause_when_in_background);
-    ReadBasicSetting(UISettings::values.mute_when_in_background);
-    ReadBasicSetting(UISettings::values.hide_mouse);
-    ReadBasicSetting(UISettings::values.controller_applet_disabled);
-    ReadBasicSetting(UISettings::values.disable_web_applet);
+    ReadCategory(Settings::Category::Ui);
+    ReadCategory(Settings::Category::UiGeneral);
 
     qt_config->endGroup();
 }
@@ -912,16 +662,8 @@ void Config::ReadUIValues() {
 void Config::ReadUIGamelistValues() {
     qt_config->beginGroup(QStringLiteral("UIGameList"));
 
-    ReadBasicSetting(UISettings::values.show_add_ons);
-    ReadBasicSetting(UISettings::values.show_compat);
-    ReadBasicSetting(UISettings::values.show_size);
-    ReadBasicSetting(UISettings::values.show_types);
-    ReadBasicSetting(UISettings::values.game_icon_size);
-    ReadBasicSetting(UISettings::values.folder_icon_size);
-    ReadBasicSetting(UISettings::values.row_1_text_id);
-    ReadBasicSetting(UISettings::values.row_2_text_id);
-    ReadBasicSetting(UISettings::values.cache_game_list);
-    ReadBasicSetting(UISettings::values.favorites_expanded);
+    ReadCategory(Settings::Category::UiGameList);
+
     const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites"));
     for (int i = 0; i < favorites_size; i++) {
         qt_config->setArrayIndex(i);
@@ -944,7 +686,8 @@ void Config::ReadUILayoutValues() {
         ReadSetting(QStringLiteral("gameListHeaderState")).toByteArray();
     UISettings::values.microprofile_geometry =
         ReadSetting(QStringLiteral("microProfileDialogGeometry")).toByteArray();
-    ReadBasicSetting(UISettings::values.microprofile_visible);
+
+    ReadCategory(Settings::Category::UiLayout);
 
     qt_config->endGroup();
 }
@@ -952,10 +695,7 @@ void Config::ReadUILayoutValues() {
 void Config::ReadWebServiceValues() {
     qt_config->beginGroup(QStringLiteral("WebService"));
 
-    ReadBasicSetting(Settings::values.enable_telemetry);
-    ReadBasicSetting(Settings::values.web_api_url);
-    ReadBasicSetting(Settings::values.yuzu_username);
-    ReadBasicSetting(Settings::values.yuzu_token);
+    ReadCategory(Settings::Category::WebService);
 
     qt_config->endGroup();
 }
@@ -963,17 +703,7 @@ void Config::ReadWebServiceValues() {
 void Config::ReadMultiplayerValues() {
     qt_config->beginGroup(QStringLiteral("Multiplayer"));
 
-    ReadBasicSetting(UISettings::values.multiplayer_nickname);
-    ReadBasicSetting(UISettings::values.multiplayer_ip);
-    ReadBasicSetting(UISettings::values.multiplayer_port);
-    ReadBasicSetting(UISettings::values.multiplayer_room_nickname);
-    ReadBasicSetting(UISettings::values.multiplayer_room_name);
-    ReadBasicSetting(UISettings::values.multiplayer_room_port);
-    ReadBasicSetting(UISettings::values.multiplayer_host_type);
-    ReadBasicSetting(UISettings::values.multiplayer_port);
-    ReadBasicSetting(UISettings::values.multiplayer_max_player);
-    ReadBasicSetting(UISettings::values.multiplayer_game_id);
-    ReadBasicSetting(UISettings::values.multiplayer_room_description);
+    ReadCategory(Settings::Category::Multiplayer);
 
     // Read ban list back
     int size = qt_config->beginReadArray(QStringLiteral("username_ban_list"));
@@ -996,11 +726,20 @@ void Config::ReadMultiplayerValues() {
     qt_config->endGroup();
 }
 
+void Config::ReadNetworkValues() {
+    qt_config->beginGroup(QString::fromStdString("Services"));
+
+    ReadCategory(Settings::Category::Network);
+
+    qt_config->endGroup();
+}
+
 void Config::ReadValues() {
     if (global) {
         ReadDataStorageValues();
         ReadDebuggingValues();
         ReadDisabledAddOnValues();
+        ReadNetworkValues();
         ReadServiceValues();
         ReadUIValues();
         ReadWebServiceValues();
@@ -1077,14 +816,9 @@ void Config::SavePlayerValue(std::size_t player_index) {
                      QString::fromStdString(player.motions[i]),
                      QString::fromStdString(default_param));
     }
-
-    if (player_index == 0) {
-        SaveMousePanningValues();
-    }
 }
 
 void Config::SaveDebugValues() {
-    WriteBasicSetting(Settings::values.debug_pad_enabled);
     for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
         const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
         WriteSetting(QStringLiteral("debug_pad_") +
@@ -1103,10 +837,6 @@ void Config::SaveDebugValues() {
     }
 }
 
-void Config::SaveMouseValues() {
-    WriteBasicSetting(Settings::values.mouse_enabled);
-}
-
 void Config::SaveTouchscreenValues() {
     const auto& touchscreen = Settings::values.touchscreen;
 
@@ -1117,21 +847,7 @@ void Config::SaveTouchscreenValues() {
     WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15);
 }
 
-void Config::SaveMousePanningValues() {
-    // Don't overwrite values.mouse_panning
-    WriteBasicSetting(Settings::values.mouse_panning_x_sensitivity);
-    WriteBasicSetting(Settings::values.mouse_panning_y_sensitivity);
-    WriteBasicSetting(Settings::values.mouse_panning_deadzone_counterweight);
-    WriteBasicSetting(Settings::values.mouse_panning_decay_strength);
-    WriteBasicSetting(Settings::values.mouse_panning_min_decay);
-}
-
 void Config::SaveMotionTouchValues() {
-    WriteBasicSetting(Settings::values.touch_device);
-    WriteBasicSetting(Settings::values.touch_from_button_map_index);
-    WriteBasicSetting(Settings::values.udp_input_servers);
-    WriteBasicSetting(Settings::values.enable_udp_controller);
-
     qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps"));
     for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
         qt_config->setArrayIndex(static_cast<int>(p));
@@ -1152,8 +868,6 @@ void Config::SaveMotionTouchValues() {
 }
 
 void Config::SaveHidbusValues() {
-    WriteBasicSetting(Settings::values.enable_ring_controller);
-
     const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
         0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
     WriteSetting(QStringLiteral("ring_controller"),
@@ -1161,11 +875,6 @@ void Config::SaveHidbusValues() {
                  QString::fromStdString(default_param));
 }
 
-void Config::SaveIrCameraValues() {
-    WriteBasicSetting(Settings::values.enable_ir_sensor);
-    WriteBasicSetting(Settings::values.ir_sensor_device);
-}
-
 void Config::SaveValues() {
     if (global) {
         SaveDataStorageValues();
@@ -1182,18 +891,14 @@ void Config::SaveValues() {
     SaveRendererValues();
     SaveAudioValues();
     SaveSystemValues();
+
     qt_config->sync();
 }
 
 void Config::SaveAudioValues() {
     qt_config->beginGroup(QStringLiteral("Audio"));
 
-    if (global) {
-        WriteBasicSetting(Settings::values.sink_id);
-        WriteBasicSetting(Settings::values.audio_output_device_id);
-        WriteBasicSetting(Settings::values.audio_input_device_id);
-    }
-    WriteGlobalSetting(Settings::values.volume);
+    WriteCategory(Settings::Category::Audio);
 
     qt_config->endGroup();
 }
@@ -1201,6 +906,8 @@ void Config::SaveAudioValues() {
 void Config::SaveControlValues() {
     qt_config->beginGroup(QStringLiteral("Controls"));
 
+    WriteCategory(Settings::Category::Controls);
+
     Settings::values.players.SetGlobal(!IsCustomConfig());
     for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
         SavePlayerValue(p);
@@ -1210,28 +917,9 @@ void Config::SaveControlValues() {
         return;
     }
     SaveDebugValues();
-    SaveMouseValues();
     SaveTouchscreenValues();
-    SaveMousePanningValues();
     SaveMotionTouchValues();
     SaveHidbusValues();
-    SaveIrCameraValues();
-
-    WriteGlobalSetting(Settings::values.use_docked_mode);
-    WriteGlobalSetting(Settings::values.vibration_enabled);
-    WriteGlobalSetting(Settings::values.enable_accurate_vibrations);
-    WriteGlobalSetting(Settings::values.motion_enabled);
-    WriteBasicSetting(Settings::values.enable_raw_input);
-    WriteBasicSetting(Settings::values.enable_joycon_driver);
-    WriteBasicSetting(Settings::values.enable_procon_driver);
-    WriteBasicSetting(Settings::values.random_amiibo_id);
-    WriteBasicSetting(Settings::values.keyboard_enabled);
-    WriteBasicSetting(Settings::values.emulate_analog_keyboard);
-    WriteBasicSetting(Settings::values.controller_navigation);
-
-    WriteBasicSetting(Settings::values.tas_enable);
-    WriteBasicSetting(Settings::values.tas_loop);
-    WriteBasicSetting(Settings::values.pause_tas_on_load);
 
     qt_config->endGroup();
 }
@@ -1239,8 +927,7 @@ void Config::SaveControlValues() {
 void Config::SaveCoreValues() {
     qt_config->beginGroup(QStringLiteral("Core"));
 
-    WriteGlobalSetting(Settings::values.use_multi_core);
-    WriteGlobalSetting(Settings::values.use_unsafe_extended_memory_layout);
+    WriteCategory(Settings::Category::Core);
 
     qt_config->endGroup();
 }
@@ -1248,7 +935,6 @@ void Config::SaveCoreValues() {
 void Config::SaveDataStorageValues() {
     qt_config->beginGroup(QStringLiteral("Data Storage"));
 
-    WriteBasicSetting(Settings::values.use_virtual_sd);
     WriteSetting(QStringLiteral("nand_directory"),
                  QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)),
                  QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
@@ -1265,9 +951,7 @@ void Config::SaveDataStorageValues() {
                  QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir)),
                  QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir)));
 
-    WriteBasicSetting(Settings::values.gamecard_inserted);
-    WriteBasicSetting(Settings::values.gamecard_current_game);
-    WriteBasicSetting(Settings::values.gamecard_path);
+    WriteCategory(Settings::Category::DataStorage);
 
     qt_config->endGroup();
 }
@@ -1277,19 +961,9 @@ void Config::SaveDebuggingValues() {
 
     // Intentionally not using the QT default setting as this is intended to be changed in the ini
     qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times);
-    WriteBasicSetting(Settings::values.use_gdbstub);
-    WriteBasicSetting(Settings::values.gdbstub_port);
-    WriteBasicSetting(Settings::values.program_args);
-    WriteBasicSetting(Settings::values.dump_exefs);
-    WriteBasicSetting(Settings::values.dump_nso);
-    WriteBasicSetting(Settings::values.enable_fs_access_log);
-    WriteBasicSetting(Settings::values.quest_flag);
-    WriteBasicSetting(Settings::values.use_debug_asserts);
-    WriteBasicSetting(Settings::values.disable_macro_jit);
-    WriteBasicSetting(Settings::values.disable_macro_hle);
-    WriteBasicSetting(Settings::values.enable_all_controllers);
-    WriteBasicSetting(Settings::values.create_crash_dumps);
-    WriteBasicSetting(Settings::values.perform_vulkan_check);
+
+    WriteCategory(Settings::Category::Debugging);
+    WriteCategory(Settings::Category::DebuggingGraphics);
 
     qt_config->endGroup();
 }
@@ -1297,7 +971,7 @@ void Config::SaveDebuggingValues() {
 void Config::SaveNetworkValues() {
     qt_config->beginGroup(QStringLiteral("Services"));
 
-    WriteBasicSetting(Settings::values.network_interface);
+    WriteCategory(Settings::Category::Network);
 
     qt_config->endGroup();
 }
@@ -1324,8 +998,7 @@ void Config::SaveDisabledAddOnValues() {
 void Config::SaveMiscellaneousValues() {
     qt_config->beginGroup(QStringLiteral("Miscellaneous"));
 
-    WriteBasicSetting(Settings::values.log_filter);
-    WriteBasicSetting(Settings::values.use_dev_keys);
+    WriteCategory(Settings::Category::Miscellaneous);
 
     qt_config->endGroup();
 }
@@ -1353,34 +1026,9 @@ void Config::SavePathValues() {
 void Config::SaveCpuValues() {
     qt_config->beginGroup(QStringLiteral("Cpu"));
 
-    WriteBasicSetting(Settings::values.cpu_accuracy_first_time);
-    WriteSetting(QStringLiteral("cpu_accuracy"),
-                 static_cast<u32>(Settings::values.cpu_accuracy.GetValue(global)),
-                 static_cast<u32>(Settings::values.cpu_accuracy.GetDefault()),
-                 Settings::values.cpu_accuracy.UsingGlobal());
-
-    WriteGlobalSetting(Settings::values.cpuopt_unsafe_unfuse_fma);
-    WriteGlobalSetting(Settings::values.cpuopt_unsafe_reduce_fp_error);
-    WriteGlobalSetting(Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
-    WriteGlobalSetting(Settings::values.cpuopt_unsafe_inaccurate_nan);
-    WriteGlobalSetting(Settings::values.cpuopt_unsafe_fastmem_check);
-    WriteGlobalSetting(Settings::values.cpuopt_unsafe_ignore_global_monitor);
-
-    if (global) {
-        WriteBasicSetting(Settings::values.cpu_debug_mode);
-        WriteBasicSetting(Settings::values.cpuopt_page_tables);
-        WriteBasicSetting(Settings::values.cpuopt_block_linking);
-        WriteBasicSetting(Settings::values.cpuopt_return_stack_buffer);
-        WriteBasicSetting(Settings::values.cpuopt_fast_dispatcher);
-        WriteBasicSetting(Settings::values.cpuopt_context_elimination);
-        WriteBasicSetting(Settings::values.cpuopt_const_prop);
-        WriteBasicSetting(Settings::values.cpuopt_misc_ir);
-        WriteBasicSetting(Settings::values.cpuopt_reduce_misalign_checks);
-        WriteBasicSetting(Settings::values.cpuopt_fastmem);
-        WriteBasicSetting(Settings::values.cpuopt_fastmem_exclusives);
-        WriteBasicSetting(Settings::values.cpuopt_recompile_exclusives);
-        WriteBasicSetting(Settings::values.cpuopt_ignore_memory_aborts);
-    }
+    WriteCategory(Settings::Category::Cpu);
+    WriteCategory(Settings::Category::CpuDebug);
+    WriteCategory(Settings::Category::CpuUnsafe);
 
     qt_config->endGroup();
 }
@@ -1388,76 +1036,9 @@ void Config::SaveCpuValues() {
 void Config::SaveRendererValues() {
     qt_config->beginGroup(QStringLiteral("Renderer"));
 
-    WriteSetting(QString::fromStdString(Settings::values.renderer_backend.GetLabel()),
-                 static_cast<u32>(Settings::values.renderer_backend.GetValue(global)),
-                 static_cast<u32>(Settings::values.renderer_backend.GetDefault()),
-                 Settings::values.renderer_backend.UsingGlobal());
-    WriteGlobalSetting(Settings::values.async_presentation);
-    WriteGlobalSetting(Settings::values.renderer_force_max_clock);
-    WriteGlobalSetting(Settings::values.vulkan_device);
-    WriteSetting(QString::fromStdString(Settings::values.fullscreen_mode.GetLabel()),
-                 static_cast<u32>(Settings::values.fullscreen_mode.GetValue(global)),
-                 static_cast<u32>(Settings::values.fullscreen_mode.GetDefault()),
-                 Settings::values.fullscreen_mode.UsingGlobal());
-    WriteGlobalSetting(Settings::values.aspect_ratio);
-    WriteSetting(QString::fromStdString(Settings::values.resolution_setup.GetLabel()),
-                 static_cast<u32>(Settings::values.resolution_setup.GetValue(global)),
-                 static_cast<u32>(Settings::values.resolution_setup.GetDefault()),
-                 Settings::values.resolution_setup.UsingGlobal());
-    WriteSetting(QString::fromStdString(Settings::values.scaling_filter.GetLabel()),
-                 static_cast<u32>(Settings::values.scaling_filter.GetValue(global)),
-                 static_cast<u32>(Settings::values.scaling_filter.GetDefault()),
-                 Settings::values.scaling_filter.UsingGlobal());
-    WriteSetting(QString::fromStdString(Settings::values.fsr_sharpening_slider.GetLabel()),
-                 static_cast<u32>(Settings::values.fsr_sharpening_slider.GetValue(global)),
-                 static_cast<u32>(Settings::values.fsr_sharpening_slider.GetDefault()),
-                 Settings::values.fsr_sharpening_slider.UsingGlobal());
-    WriteSetting(QString::fromStdString(Settings::values.anti_aliasing.GetLabel()),
-                 static_cast<u32>(Settings::values.anti_aliasing.GetValue(global)),
-                 static_cast<u32>(Settings::values.anti_aliasing.GetDefault()),
-                 Settings::values.anti_aliasing.UsingGlobal());
-    WriteGlobalSetting(Settings::values.max_anisotropy);
-    WriteGlobalSetting(Settings::values.speed_limit);
-    WriteGlobalSetting(Settings::values.use_disk_shader_cache);
-    WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()),
-                 static_cast<u32>(Settings::values.gpu_accuracy.GetValue(global)),
-                 static_cast<u32>(Settings::values.gpu_accuracy.GetDefault()),
-                 Settings::values.gpu_accuracy.UsingGlobal());
-    WriteGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
-    WriteSetting(QString::fromStdString(Settings::values.nvdec_emulation.GetLabel()),
-                 static_cast<u32>(Settings::values.nvdec_emulation.GetValue(global)),
-                 static_cast<u32>(Settings::values.nvdec_emulation.GetDefault()),
-                 Settings::values.nvdec_emulation.UsingGlobal());
-    WriteGlobalSetting(Settings::values.accelerate_astc);
-    WriteGlobalSetting(Settings::values.async_astc);
-    WriteSetting(QString::fromStdString(Settings::values.astc_recompression.GetLabel()),
-                 static_cast<u32>(Settings::values.astc_recompression.GetValue(global)),
-                 static_cast<u32>(Settings::values.astc_recompression.GetDefault()),
-                 Settings::values.astc_recompression.UsingGlobal());
-    WriteGlobalSetting(Settings::values.use_reactive_flushing);
-    WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()),
-                 static_cast<u32>(Settings::values.shader_backend.GetValue(global)),
-                 static_cast<u32>(Settings::values.shader_backend.GetDefault()),
-                 Settings::values.shader_backend.UsingGlobal());
-    WriteGlobalSetting(Settings::values.use_asynchronous_shaders);
-    WriteGlobalSetting(Settings::values.use_fast_gpu_time);
-    WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);
-    WriteGlobalSetting(Settings::values.enable_compute_pipelines);
-    WriteGlobalSetting(Settings::values.use_video_framerate);
-    WriteGlobalSetting(Settings::values.barrier_feedback_loops);
-    WriteGlobalSetting(Settings::values.bg_red);
-    WriteGlobalSetting(Settings::values.bg_green);
-    WriteGlobalSetting(Settings::values.bg_blue);
-
-    if (global) {
-        WriteSetting(QString::fromStdString(Settings::values.vsync_mode.GetLabel()),
-                     static_cast<u32>(Settings::values.vsync_mode.GetValue()),
-                     static_cast<u32>(Settings::values.vsync_mode.GetDefault()));
-        WriteBasicSetting(Settings::values.renderer_debug);
-        WriteBasicSetting(Settings::values.renderer_shader_feedback);
-        WriteBasicSetting(Settings::values.enable_nsight_aftermath);
-        WriteBasicSetting(Settings::values.disable_shader_loop_safety_checks);
-    }
+    WriteCategory(Settings::Category::Renderer);
+    WriteCategory(Settings::Category::RendererAdvanced);
+    WriteCategory(Settings::Category::RendererDebug);
 
     qt_config->endGroup();
 }
@@ -1465,9 +1046,9 @@ void Config::SaveRendererValues() {
 void Config::SaveScreenshotValues() {
     qt_config->beginGroup(QStringLiteral("Screenshots"));
 
-    WriteBasicSetting(UISettings::values.enable_screenshot_save_as);
     WriteSetting(QStringLiteral("screenshot_path"),
                  QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)));
+    WriteCategory(Settings::Category::Screenshots);
 
     qt_config->endGroup();
 }
@@ -1498,27 +1079,8 @@ void Config::SaveShortcutValues() {
 void Config::SaveSystemValues() {
     qt_config->beginGroup(QStringLiteral("System"));
 
-    WriteGlobalSetting(Settings::values.language_index);
-    WriteGlobalSetting(Settings::values.region_index);
-    WriteGlobalSetting(Settings::values.time_zone_index);
-
-    WriteSetting(QStringLiteral("rng_seed_enabled"),
-                 Settings::values.rng_seed.GetValue(global).has_value(), false,
-                 Settings::values.rng_seed.UsingGlobal());
-    WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.GetValue(global).value_or(0),
-                 0, Settings::values.rng_seed.UsingGlobal());
-
-    if (global) {
-        WriteBasicSetting(Settings::values.current_user);
-
-        WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(),
-                     false);
-        WriteSetting(QStringLiteral("custom_rtc"),
-                     QVariant::fromValue<long long>(Settings::values.custom_rtc.value_or(0)), 0);
-        WriteBasicSetting(Settings::values.device_name);
-    }
-
-    WriteGlobalSetting(Settings::values.sound_index);
+    WriteCategory(Settings::Category::System);
+    WriteCategory(Settings::Category::SystemAudio);
 
     qt_config->endGroup();
 }
@@ -1526,10 +1088,11 @@ void Config::SaveSystemValues() {
 void Config::SaveUIValues() {
     qt_config->beginGroup(QStringLiteral("UI"));
 
+    WriteCategory(Settings::Category::Ui);
+    WriteCategory(Settings::Category::UiGeneral);
+
     WriteSetting(QStringLiteral("theme"), UISettings::values.theme,
                  QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second));
-    WriteBasicSetting(UISettings::values.enable_discord_presence);
-    WriteBasicSetting(UISettings::values.select_user_on_boot);
 
     SaveUIGamelistValues();
     SaveUILayoutValues();
@@ -1538,37 +1101,14 @@ void Config::SaveUIValues() {
     SaveShortcutValues();
     SaveMultiplayerValues();
 
-    WriteBasicSetting(UISettings::values.single_window_mode);
-    WriteBasicSetting(UISettings::values.fullscreen);
-    WriteBasicSetting(UISettings::values.display_titlebar);
-    WriteBasicSetting(UISettings::values.show_filter_bar);
-    WriteBasicSetting(UISettings::values.show_status_bar);
-    WriteBasicSetting(UISettings::values.confirm_before_closing);
-    WriteBasicSetting(UISettings::values.first_start);
-    WriteBasicSetting(UISettings::values.callout_flags);
-    WriteBasicSetting(UISettings::values.show_console);
-    WriteBasicSetting(UISettings::values.pause_when_in_background);
-    WriteBasicSetting(UISettings::values.mute_when_in_background);
-    WriteBasicSetting(UISettings::values.hide_mouse);
-    WriteBasicSetting(UISettings::values.controller_applet_disabled);
-    WriteBasicSetting(UISettings::values.disable_web_applet);
-
     qt_config->endGroup();
 }
 
 void Config::SaveUIGamelistValues() {
     qt_config->beginGroup(QStringLiteral("UIGameList"));
 
-    WriteBasicSetting(UISettings::values.show_add_ons);
-    WriteBasicSetting(UISettings::values.show_compat);
-    WriteBasicSetting(UISettings::values.show_size);
-    WriteBasicSetting(UISettings::values.show_types);
-    WriteBasicSetting(UISettings::values.game_icon_size);
-    WriteBasicSetting(UISettings::values.folder_icon_size);
-    WriteBasicSetting(UISettings::values.row_1_text_id);
-    WriteBasicSetting(UISettings::values.row_2_text_id);
-    WriteBasicSetting(UISettings::values.cache_game_list);
-    WriteBasicSetting(UISettings::values.favorites_expanded);
+    WriteCategory(Settings::Category::UiGameList);
+
     qt_config->beginWriteArray(QStringLiteral("favorites"));
     for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) {
         qt_config->setArrayIndex(i);
@@ -1589,7 +1129,8 @@ void Config::SaveUILayoutValues() {
     WriteSetting(QStringLiteral("gameListHeaderState"), UISettings::values.gamelist_header_state);
     WriteSetting(QStringLiteral("microProfileDialogGeometry"),
                  UISettings::values.microprofile_geometry);
-    WriteBasicSetting(UISettings::values.microprofile_visible);
+
+    WriteCategory(Settings::Category::UiLayout);
 
     qt_config->endGroup();
 }
@@ -1597,10 +1138,7 @@ void Config::SaveUILayoutValues() {
 void Config::SaveWebServiceValues() {
     qt_config->beginGroup(QStringLiteral("WebService"));
 
-    WriteBasicSetting(Settings::values.enable_telemetry);
-    WriteBasicSetting(Settings::values.web_api_url);
-    WriteBasicSetting(Settings::values.yuzu_username);
-    WriteBasicSetting(Settings::values.yuzu_token);
+    WriteCategory(Settings::Category::WebService);
 
     qt_config->endGroup();
 }
@@ -1608,17 +1146,7 @@ void Config::SaveWebServiceValues() {
 void Config::SaveMultiplayerValues() {
     qt_config->beginGroup(QStringLiteral("Multiplayer"));
 
-    WriteBasicSetting(UISettings::values.multiplayer_nickname);
-    WriteBasicSetting(UISettings::values.multiplayer_ip);
-    WriteBasicSetting(UISettings::values.multiplayer_port);
-    WriteBasicSetting(UISettings::values.multiplayer_room_nickname);
-    WriteBasicSetting(UISettings::values.multiplayer_room_name);
-    WriteBasicSetting(UISettings::values.multiplayer_room_port);
-    WriteBasicSetting(UISettings::values.multiplayer_host_type);
-    WriteBasicSetting(UISettings::values.multiplayer_port);
-    WriteBasicSetting(UISettings::values.multiplayer_max_player);
-    WriteBasicSetting(UISettings::values.multiplayer_game_id);
-    WriteBasicSetting(UISettings::values.multiplayer_room_description);
+    WriteCategory(Settings::Category::Multiplayer);
 
     // Write ban list
     qt_config->beginWriteArray(QStringLiteral("username_ban_list"));
@@ -1653,27 +1181,6 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value)
     return result;
 }
 
-template <typename Type, bool ranged>
-void Config::ReadGlobalSetting(Settings::SwitchableSetting<Type, ranged>& setting) {
-    QString name = QString::fromStdString(setting.GetLabel());
-    const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
-    setting.SetGlobal(use_global);
-    if (global || !use_global) {
-        setting.SetValue(static_cast<QVariant>(
-                             ReadSetting(name, QVariant::fromValue<Type>(setting.GetDefault())))
-                             .value<Type>());
-    }
-}
-
-template <typename Type>
-void Config::ReadSettingGlobal(Type& setting, const QString& name,
-                               const QVariant& default_value) const {
-    const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
-    if (global || !use_global) {
-        setting = ReadSetting(name, default_value).value<Type>();
-    }
-}
-
 void Config::WriteSetting(const QString& name, const QVariant& value) {
     qt_config->setValue(name, value);
 }
@@ -1727,3 +1234,72 @@ void Config::ClearControlPlayerValues() {
 const std::string& Config::GetConfigFilePath() const {
     return qt_config_loc;
 }
+
+static auto FindRelevantList(Settings::Category category) {
+    auto& map = Settings::values.linkage.by_category;
+    if (map.contains(category)) {
+        return Settings::values.linkage.by_category[category];
+    }
+    return UISettings::values.linkage.by_category[category];
+}
+
+void Config::ReadCategory(Settings::Category category) {
+    const auto& settings = FindRelevantList(category);
+    std::for_each(settings.begin(), settings.end(),
+                  [&](const auto& setting) { ReadSettingGeneric(setting); });
+}
+
+void Config::WriteCategory(Settings::Category category) {
+    const auto& settings = FindRelevantList(category);
+    std::for_each(settings.begin(), settings.end(),
+                  [&](const auto& setting) { WriteSettingGeneric(setting); });
+}
+
+void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) {
+    if (!setting->Save() || (!setting->Switchable() && !global)) {
+        return;
+    }
+    const QString name = QString::fromStdString(setting->GetLabel());
+    const auto default_value =
+        QVariant::fromValue<QString>(QString::fromStdString(setting->DefaultToString()));
+
+    bool use_global = true;
+    if (setting->Switchable() && !global) {
+        use_global = qt_config->value(name + QStringLiteral("/use_global"), true).value<bool>();
+        setting->SetGlobal(use_global);
+    }
+
+    if (global || !use_global) {
+        const bool is_default =
+            qt_config->value(name + QStringLiteral("/default"), true).value<bool>();
+        if (!is_default) {
+            setting->LoadString(
+                qt_config->value(name, default_value).value<QString>().toStdString());
+        } else {
+            // Empty string resets the Setting to default
+            setting->LoadString("");
+        }
+    }
+}
+
+void Config::WriteSettingGeneric(Settings::BasicSetting* const setting) const {
+    if (!setting->Save()) {
+        return;
+    }
+    const QVariant value = QVariant::fromValue(QString::fromStdString(setting->ToString()));
+    const QVariant default_value =
+        QVariant::fromValue(QString::fromStdString(setting->DefaultToString()));
+    const QString label = QString::fromStdString(setting->GetLabel());
+    if (setting->Switchable()) {
+        if (!global) {
+            qt_config->setValue(label + QStringLiteral("/use_global"), setting->UsingGlobal());
+        }
+        if (global || !setting->UsingGlobal()) {
+            qt_config->setValue(label + QStringLiteral("/default"), value == default_value);
+            qt_config->setValue(label, value);
+        }
+    } else if (global) {
+        qt_config->setValue(label + QStringLiteral("/default"), value == default_value);
+        qt_config->setValue(label, value);
+    }
+}
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 1211389d27..0ac74c8e72 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -52,7 +52,7 @@ public:
     static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map;
     static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map;
     static const std::map<bool, QString> use_docked_mode_texts_map;
-    static const std::map<Settings::GPUAccuracy, QString> gpu_accuracy_texts_map;
+    static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map;
     static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map;
     static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map;
 
@@ -74,7 +74,6 @@ private:
     void ReadKeyboardValues();
     void ReadMouseValues();
     void ReadTouchscreenValues();
-    void ReadMousePanningValues();
     void ReadMotionTouchValues();
     void ReadHidbusValues();
     void ReadIrCameraValues();
@@ -99,13 +98,13 @@ private:
     void ReadUILayoutValues();
     void ReadWebServiceValues();
     void ReadMultiplayerValues();
+    void ReadNetworkValues();
 
     void SaveValues();
     void SavePlayerValue(std::size_t player_index);
     void SaveDebugValues();
     void SaveMouseValues();
     void SaveTouchscreenValues();
-    void SaveMousePanningValues();
     void SaveMotionTouchValues();
     void SaveHidbusValues();
     void SaveIrCameraValues();
@@ -140,18 +139,6 @@ private:
     QVariant ReadSetting(const QString& name) const;
     QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
 
-    /**
-     * Only reads a setting from the qt_config if the current config is a global config, or if the
-     * current config is a custom config and the setting is overriding the global setting. Otherwise
-     * it does nothing.
-     *
-     * @param setting The variable to be modified
-     * @param name The setting's identifier
-     * @param default_value The value to use when the setting is not already present in the config
-     */
-    template <typename Type>
-    void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const;
-
     /**
      * Writes a setting to the qt_config.
      *
@@ -166,50 +153,20 @@ private:
     void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
                       bool use_global);
 
-    /**
-     * Reads a value from the qt_config and applies it to the setting, using its label and default
-     * value. If the config is a custom config, this will also read the global state of the setting
-     * and apply that information to it.
-     *
-     * @param The setting
-     */
-    template <typename Type, bool ranged>
-    void ReadGlobalSetting(Settings::SwitchableSetting<Type, ranged>& setting);
+    void ReadCategory(Settings::Category category);
+    void WriteCategory(Settings::Category category);
+    void ReadSettingGeneric(Settings::BasicSetting* const setting);
+    void WriteSettingGeneric(Settings::BasicSetting* const setting) const;
 
-    /**
-     * Sets a value to the qt_config using the setting's label and default value. If the config is a
-     * custom config, it will apply the global state, and the custom value if needed.
-     *
-     * @param The setting
-     */
-    template <typename Type, bool ranged>
-    void WriteGlobalSetting(const Settings::SwitchableSetting<Type, ranged>& setting);
-
-    /**
-     * Reads a value from the qt_config using the setting's label and default value and applies the
-     * value to the setting.
-     *
-     * @param The setting
-     */
-    template <typename Type, bool ranged>
-    void ReadBasicSetting(Settings::Setting<Type, ranged>& setting);
-
-    /** Sets a value from the setting in the qt_config using the setting's label and default value.
-     *
-     * @param The setting
-     */
-    template <typename Type, bool ranged>
-    void WriteBasicSetting(const Settings::Setting<Type, ranged>& setting);
-
-    ConfigType type;
+    const ConfigType type;
     std::unique_ptr<QSettings> qt_config;
     std::string qt_config_loc;
-    bool global;
+    const bool global;
 };
 
 // These metatype declarations cannot be in common/settings.h because core is devoid of QT
-Q_DECLARE_METATYPE(Settings::CPUAccuracy);
-Q_DECLARE_METATYPE(Settings::GPUAccuracy);
+Q_DECLARE_METATYPE(Settings::CpuAccuracy);
+Q_DECLARE_METATYPE(Settings::GpuAccuracy);
 Q_DECLARE_METATYPE(Settings::FullscreenMode);
 Q_DECLARE_METATYPE(Settings::NvdecEmulation);
 Q_DECLARE_METATYPE(Settings::ResolutionSetup);
@@ -218,3 +175,4 @@ Q_DECLARE_METATYPE(Settings::AntiAliasing);
 Q_DECLARE_METATYPE(Settings::RendererBackend);
 Q_DECLARE_METATYPE(Settings::ShaderBackend);
 Q_DECLARE_METATYPE(Settings::AstcRecompression);
+Q_DECLARE_METATYPE(Settings::AstcDecodeMode);
diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp
index ac42cc7fc2..0ed6146a0f 100644
--- a/src/yuzu/configuration/configuration_shared.cpp
+++ b/src/yuzu/configuration/configuration_shared.cpp
@@ -1,104 +1,19 @@
 // SPDX-FileCopyrightText: 2016 Citra Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
-#include <QCheckBox>
-#include <QObject>
-#include <QString>
-#include "common/settings.h"
+#include <memory>
+#include <type_traits>
+#include <vector>
 #include "yuzu/configuration/configuration_shared.h"
-#include "yuzu/configuration/configure_per_game.h"
 
-void ConfigurationShared::ApplyPerGameSetting(Settings::SwitchableSetting<bool>* setting,
-                                              const QCheckBox* checkbox,
-                                              const CheckState& tracker) {
-    if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
-        setting->SetValue(checkbox->checkState());
-    } else if (!Settings::IsConfiguringGlobal()) {
-        if (tracker == CheckState::Global) {
-            setting->SetGlobal(true);
-        } else {
-            setting->SetGlobal(false);
-            setting->SetValue(checkbox->checkState());
-        }
+namespace ConfigurationShared {
+
+Tab::Tab(std::shared_ptr<std::vector<Tab*>> group, QWidget* parent) : QWidget(parent) {
+    if (group != nullptr) {
+        group->push_back(this);
     }
 }
 
-void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox,
-                                            const Settings::SwitchableSetting<bool>* setting) {
-    if (setting->UsingGlobal()) {
-        checkbox->setCheckState(Qt::PartiallyChecked);
-    } else {
-        checkbox->setCheckState(setting->GetValue() ? Qt::Checked : Qt::Unchecked);
-    }
-}
+Tab::~Tab() = default;
 
-void ConfigurationShared::SetHighlight(QWidget* widget, bool highlighted) {
-    if (highlighted) {
-        widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,203,255,0.5) }")
-                                  .arg(widget->objectName()));
-    } else {
-        widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,0,0,0) }")
-                                  .arg(widget->objectName()));
-    }
-    widget->show();
-}
-
-void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox,
-                                             const Settings::SwitchableSetting<bool>& setting,
-                                             CheckState& tracker) {
-    if (setting.UsingGlobal()) {
-        tracker = CheckState::Global;
-    } else {
-        tracker = (setting.GetValue() == setting.GetValue(true)) ? CheckState::On : CheckState::Off;
-    }
-    SetHighlight(checkbox, tracker != CheckState::Global);
-    QObject::connect(checkbox, &QCheckBox::clicked, checkbox, [checkbox, setting, &tracker] {
-        tracker = static_cast<CheckState>((static_cast<int>(tracker) + 1) %
-                                          static_cast<int>(CheckState::Count));
-        if (tracker == CheckState::Global) {
-            checkbox->setChecked(setting.GetValue(true));
-        }
-        SetHighlight(checkbox, tracker != CheckState::Global);
-    });
-}
-
-void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox, bool global, bool state,
-                                             bool global_state, CheckState& tracker) {
-    if (global) {
-        tracker = CheckState::Global;
-    } else {
-        tracker = (state == global_state) ? CheckState::On : CheckState::Off;
-    }
-    SetHighlight(checkbox, tracker != CheckState::Global);
-    QObject::connect(checkbox, &QCheckBox::clicked, checkbox, [checkbox, global_state, &tracker] {
-        tracker = static_cast<CheckState>((static_cast<int>(tracker) + 1) %
-                                          static_cast<int>(CheckState::Count));
-        if (tracker == CheckState::Global) {
-            checkbox->setChecked(global_state);
-        }
-        SetHighlight(checkbox, tracker != CheckState::Global);
-    });
-}
-
-void ConfigurationShared::SetColoredComboBox(QComboBox* combobox, QWidget* target, int global) {
-    InsertGlobalItem(combobox, global);
-    QObject::connect(combobox, qOverload<int>(&QComboBox::activated), target,
-                     [target](int index) { SetHighlight(target, index != 0); });
-}
-
-void ConfigurationShared::InsertGlobalItem(QComboBox* combobox, int global_index) {
-    const QString use_global_text =
-        ConfigurePerGame::tr("Use global configuration (%1)").arg(combobox->itemText(global_index));
-    combobox->insertItem(ConfigurationShared::USE_GLOBAL_INDEX, use_global_text);
-    combobox->insertSeparator(ConfigurationShared::USE_GLOBAL_SEPARATOR_INDEX);
-}
-
-int ConfigurationShared::GetComboboxIndex(int global_setting_index, const QComboBox* combobox) {
-    if (Settings::IsConfiguringGlobal()) {
-        return combobox->currentIndex();
-    }
-    if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
-        return global_setting_index;
-    }
-    return combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET;
-}
+} // namespace ConfigurationShared
diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h
index 04c88758c6..31897a6b0a 100644
--- a/src/yuzu/configuration/configuration_shared.h
+++ b/src/yuzu/configuration/configuration_shared.h
@@ -3,73 +3,25 @@
 
 #pragma once
 
-#include <QCheckBox>
-#include <QComboBox>
-#include "common/settings.h"
+#include <memory>
+#include <vector>
+#include <QString>
+#include <QWidget>
+#include <qobjectdefs.h>
+
+class QObject;
 
 namespace ConfigurationShared {
 
-constexpr int USE_GLOBAL_INDEX = 0;
-constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1;
-constexpr int USE_GLOBAL_OFFSET = 2;
+class Tab : public QWidget {
+    Q_OBJECT
 
-// CheckBoxes require a tracker for their state since we emulate a tristate CheckBox
-enum class CheckState {
-    Off,    // Checkbox overrides to off/false
-    On,     // Checkbox overrides to on/true
-    Global, // Checkbox defers to the global state
-    Count,  // Simply the number of states, not a valid checkbox state
+public:
+    explicit Tab(std::shared_ptr<std::vector<Tab*>> group, QWidget* parent = nullptr);
+    ~Tab();
+
+    virtual void ApplyConfiguration() = 0;
+    virtual void SetConfiguration() = 0;
 };
 
-// Global-aware apply and set functions
-
-// ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting
-void ApplyPerGameSetting(Settings::SwitchableSetting<bool>* setting, const QCheckBox* checkbox,
-                         const CheckState& tracker);
-template <typename Type, bool ranged>
-void ApplyPerGameSetting(Settings::SwitchableSetting<Type, ranged>* setting,
-                         const QComboBox* combobox) {
-    if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
-        setting->SetValue(static_cast<Type>(combobox->currentIndex()));
-    } else if (!Settings::IsConfiguringGlobal()) {
-        if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
-            setting->SetGlobal(true);
-        } else {
-            setting->SetGlobal(false);
-            setting->SetValue(static_cast<Type>(combobox->currentIndex() -
-                                                ConfigurationShared::USE_GLOBAL_OFFSET));
-        }
-    }
-}
-
-// Sets a Qt UI element given a Settings::Setting
-void SetPerGameSetting(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>* setting);
-
-template <typename Type, bool ranged>
-void SetPerGameSetting(QComboBox* combobox,
-                       const Settings::SwitchableSetting<Type, ranged>* setting) {
-    combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
-                                                     : static_cast<int>(setting->GetValue()) +
-                                                           ConfigurationShared::USE_GLOBAL_OFFSET);
-}
-
-// (Un)highlights a Qt UI element
-void SetHighlight(QWidget* widget, bool highlighted);
-
-// Sets up a QCheckBox like a tristate one, given a Setting
-void SetColoredTristate(QCheckBox* checkbox, const Settings::SwitchableSetting<bool>& setting,
-                        CheckState& tracker);
-void SetColoredTristate(QCheckBox* checkbox, bool global, bool state, bool global_state,
-                        CheckState& tracker);
-
-// Sets up coloring of a QWidget `target` based on the state of a QComboBox, and calls
-// InsertGlobalItem
-void SetColoredComboBox(QComboBox* combobox, QWidget* target, int global);
-
-// Adds the "Use Global Configuration" selection and separator to the beginning of a QComboBox
-void InsertGlobalItem(QComboBox* combobox, int global_index);
-
-// Returns the correct index of a QComboBox taking into account global configuration
-int GetComboboxIndex(int global_setting_index, const QComboBox* combobox);
-
 } // namespace ConfigurationShared
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index eb8078467e..573c408014 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -48,11 +48,34 @@
     </layout>
    </item>
    <item>
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <property name="leftMargin">
+      <number>0</number>
      </property>
-    </widget>
+     <property name="topMargin">
+      <number>0</number>
+     </property>
+     <property name="rightMargin">
+      <number>0</number>
+     </property>
+     <property name="bottomMargin">
+      <number>0</number>
+     </property>
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Some settings are only available when a game is not running.</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QDialogButtonBox" name="buttonBox">
+       <property name="standardButtons">
+        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
    </item>
   </layout>
  </widget>
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index fcd6d61a05..9ccfb24352 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -1,87 +1,112 @@
 // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
+#include <map>
 #include <memory>
+#include <vector>
+#include <QComboBox>
 
 #include "audio_core/sink/sink.h"
 #include "audio_core/sink/sink_details.h"
+#include "common/common_types.h"
 #include "common/settings.h"
+#include "common/settings_common.h"
 #include "core/core.h"
 #include "ui_configure_audio.h"
 #include "yuzu/configuration/configuration_shared.h"
 #include "yuzu/configuration/configure_audio.h"
+#include "yuzu/configuration/shared_translation.h"
+#include "yuzu/configuration/shared_widget.h"
 #include "yuzu/uisettings.h"
 
-ConfigureAudio::ConfigureAudio(const Core::System& system_, QWidget* parent)
-    : QWidget(parent), ui(std::make_unique<Ui::ConfigureAudio>()), system{system_} {
+ConfigureAudio::ConfigureAudio(const Core::System& system_,
+                               std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
+                               const ConfigurationShared::Builder& builder, QWidget* parent)
+    : Tab(group_, parent), ui(std::make_unique<Ui::ConfigureAudio>()), system{system_} {
     ui->setupUi(this);
-
-    InitializeAudioSinkComboBox();
-
-    connect(ui->volume_slider, &QSlider::valueChanged, this,
-            &ConfigureAudio::SetVolumeIndicatorText);
-    connect(ui->sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
-            &ConfigureAudio::UpdateAudioDevices);
-
-    ui->volume_label->setVisible(Settings::IsConfiguringGlobal());
-    ui->volume_combo_box->setVisible(!Settings::IsConfiguringGlobal());
-
-    SetupPerGameUI();
+    Setup(builder);
 
     SetConfiguration();
-
-    const bool is_powered_on = system_.IsPoweredOn();
-    ui->sink_combo_box->setEnabled(!is_powered_on);
-    ui->output_combo_box->setEnabled(!is_powered_on);
-    ui->input_combo_box->setEnabled(!is_powered_on);
 }
 
 ConfigureAudio::~ConfigureAudio() = default;
 
+void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) {
+    auto& layout = *ui->audio_widget->layout();
+
+    std::vector<Settings::BasicSetting*> settings;
+
+    std::map<u32, QWidget*> hold;
+
+    auto push = [&](Settings::Category category) {
+        for (auto* setting : Settings::values.linkage.by_category[category]) {
+            settings.push_back(setting);
+        }
+    };
+
+    push(Settings::Category::Audio);
+    push(Settings::Category::SystemAudio);
+
+    for (auto* setting : settings) {
+        auto* widget = builder.BuildWidget(setting, apply_funcs);
+
+        if (widget == nullptr) {
+            continue;
+        }
+        if (!widget->Valid()) {
+            widget->deleteLater();
+            continue;
+        }
+
+        hold.emplace(std::pair{setting->Id(), widget});
+
+        if (setting->Id() == Settings::values.sink_id.Id()) {
+            // TODO (lat9nq): Let the system manage sink_id
+            sink_combo_box = widget->combobox;
+            InitializeAudioSinkComboBox();
+
+            connect(sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
+                    &ConfigureAudio::UpdateAudioDevices);
+        } else if (setting->Id() == Settings::values.audio_output_device_id.Id()) {
+            // Keep track of output (and input) device comboboxes to populate them with system
+            // devices, which are determined at run time
+            output_device_combo_box = widget->combobox;
+        } else if (setting->Id() == Settings::values.audio_input_device_id.Id()) {
+            input_device_combo_box = widget->combobox;
+        }
+    }
+
+    for (const auto& [id, widget] : hold) {
+        layout.addWidget(widget);
+    }
+}
+
 void ConfigureAudio::SetConfiguration() {
+    if (!Settings::IsConfiguringGlobal()) {
+        return;
+    }
+
     SetOutputSinkFromSinkID();
 
     // The device list cannot be pre-populated (nor listed) until the output sink is known.
-    UpdateAudioDevices(ui->sink_combo_box->currentIndex());
+    UpdateAudioDevices(sink_combo_box->currentIndex());
 
     SetAudioDevicesFromDeviceID();
-
-    const auto volume_value = static_cast<int>(Settings::values.volume.GetValue());
-    ui->volume_slider->setValue(volume_value);
-    ui->toggle_background_mute->setChecked(UISettings::values.mute_when_in_background.GetValue());
-
-    if (!Settings::IsConfiguringGlobal()) {
-        if (Settings::values.volume.UsingGlobal()) {
-            ui->volume_combo_box->setCurrentIndex(0);
-            ui->volume_slider->setEnabled(false);
-        } else {
-            ui->volume_combo_box->setCurrentIndex(1);
-            ui->volume_slider->setEnabled(true);
-        }
-        ConfigurationShared::SetPerGameSetting(ui->combo_sound, &Settings::values.sound_index);
-        ConfigurationShared::SetHighlight(ui->mode_label,
-                                          !Settings::values.sound_index.UsingGlobal());
-        ConfigurationShared::SetHighlight(ui->volume_layout,
-                                          !Settings::values.volume.UsingGlobal());
-    } else {
-        ui->combo_sound->setCurrentIndex(Settings::values.sound_index.GetValue());
-    }
-    SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
 }
 
 void ConfigureAudio::SetOutputSinkFromSinkID() {
-    [[maybe_unused]] const QSignalBlocker blocker(ui->sink_combo_box);
+    [[maybe_unused]] const QSignalBlocker blocker(sink_combo_box);
 
     int new_sink_index = 0;
-    const QString sink_id = QString::fromStdString(Settings::values.sink_id.GetValue());
-    for (int index = 0; index < ui->sink_combo_box->count(); index++) {
-        if (ui->sink_combo_box->itemText(index) == sink_id) {
+    const QString sink_id = QString::fromStdString(Settings::values.sink_id.ToString());
+    for (int index = 0; index < sink_combo_box->count(); index++) {
+        if (sink_combo_box->itemText(index) == sink_id) {
             new_sink_index = index;
             break;
         }
     }
 
-    ui->sink_combo_box->setCurrentIndex(new_sink_index);
+    sink_combo_box->setCurrentIndex(new_sink_index);
 }
 
 void ConfigureAudio::SetAudioDevicesFromDeviceID() {
@@ -89,57 +114,42 @@ void ConfigureAudio::SetAudioDevicesFromDeviceID() {
 
     const QString output_device_id =
         QString::fromStdString(Settings::values.audio_output_device_id.GetValue());
-    for (int index = 0; index < ui->output_combo_box->count(); index++) {
-        if (ui->output_combo_box->itemText(index) == output_device_id) {
+    for (int index = 0; index < output_device_combo_box->count(); index++) {
+        if (output_device_combo_box->itemText(index) == output_device_id) {
             new_device_index = index;
             break;
         }
     }
 
-    ui->output_combo_box->setCurrentIndex(new_device_index);
+    output_device_combo_box->setCurrentIndex(new_device_index);
 
     new_device_index = -1;
     const QString input_device_id =
         QString::fromStdString(Settings::values.audio_input_device_id.GetValue());
-    for (int index = 0; index < ui->input_combo_box->count(); index++) {
-        if (ui->input_combo_box->itemText(index) == input_device_id) {
+    for (int index = 0; index < input_device_combo_box->count(); index++) {
+        if (input_device_combo_box->itemText(index) == input_device_id) {
             new_device_index = index;
             break;
         }
     }
 
-    ui->input_combo_box->setCurrentIndex(new_device_index);
-}
-
-void ConfigureAudio::SetVolumeIndicatorText(int percentage) {
-    ui->volume_indicator->setText(tr("%1%", "Volume percentage (e.g. 50%)").arg(percentage));
+    input_device_combo_box->setCurrentIndex(new_device_index);
 }
 
 void ConfigureAudio::ApplyConfiguration() {
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
+    const bool is_powered_on = system.IsPoweredOn();
+    for (const auto& apply_func : apply_funcs) {
+        apply_func(is_powered_on);
+    }
 
     if (Settings::IsConfiguringGlobal()) {
-        Settings::values.sink_id =
-            ui->sink_combo_box->itemText(ui->sink_combo_box->currentIndex()).toStdString();
+        Settings::values.sink_id.LoadString(
+            sink_combo_box->itemText(sink_combo_box->currentIndex()).toStdString());
         Settings::values.audio_output_device_id.SetValue(
-            ui->output_combo_box->itemText(ui->output_combo_box->currentIndex()).toStdString());
+            output_device_combo_box->itemText(output_device_combo_box->currentIndex())
+                .toStdString());
         Settings::values.audio_input_device_id.SetValue(
-            ui->input_combo_box->itemText(ui->input_combo_box->currentIndex()).toStdString());
-        UISettings::values.mute_when_in_background = ui->toggle_background_mute->isChecked();
-
-        // Guard if during game and set to game-specific value
-        if (Settings::values.volume.UsingGlobal()) {
-            const auto volume = static_cast<u8>(ui->volume_slider->value());
-            Settings::values.volume.SetValue(volume);
-        }
-    } else {
-        if (ui->volume_combo_box->currentIndex() == 0) {
-            Settings::values.volume.SetGlobal(true);
-        } else {
-            Settings::values.volume.SetGlobal(false);
-            const auto volume = static_cast<u8>(ui->volume_slider->value());
-            Settings::values.volume.SetValue(volume);
-        }
+            input_device_combo_box->itemText(input_device_combo_box->currentIndex()).toStdString());
     }
 }
 
@@ -152,54 +162,31 @@ void ConfigureAudio::changeEvent(QEvent* event) {
 }
 
 void ConfigureAudio::UpdateAudioDevices(int sink_index) {
-    ui->output_combo_box->clear();
-    ui->output_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
+    output_device_combo_box->clear();
+    output_device_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
 
-    const std::string sink_id = ui->sink_combo_box->itemText(sink_index).toStdString();
+    const auto sink_id =
+        Settings::ToEnum<Settings::AudioEngine>(sink_combo_box->itemText(sink_index).toStdString());
     for (const auto& device : AudioCore::Sink::GetDeviceListForSink(sink_id, false)) {
-        ui->output_combo_box->addItem(QString::fromStdString(device));
+        output_device_combo_box->addItem(QString::fromStdString(device));
     }
 
-    ui->input_combo_box->clear();
-    ui->input_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
+    input_device_combo_box->clear();
+    input_device_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
     for (const auto& device : AudioCore::Sink::GetDeviceListForSink(sink_id, true)) {
-        ui->input_combo_box->addItem(QString::fromStdString(device));
+        input_device_combo_box->addItem(QString::fromStdString(device));
     }
 }
 
 void ConfigureAudio::InitializeAudioSinkComboBox() {
-    ui->sink_combo_box->clear();
-    ui->sink_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
+    sink_combo_box->clear();
+    sink_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
 
     for (const auto& id : AudioCore::Sink::GetSinkIDs()) {
-        ui->sink_combo_box->addItem(QString::fromUtf8(id.data(), static_cast<s32>(id.length())));
+        sink_combo_box->addItem(QString::fromStdString(Settings::CanonicalizeEnum(id)));
     }
 }
 
 void ConfigureAudio::RetranslateUI() {
     ui->retranslateUi(this);
-    SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
-}
-
-void ConfigureAudio::SetupPerGameUI() {
-    if (Settings::IsConfiguringGlobal()) {
-        ui->combo_sound->setEnabled(Settings::values.sound_index.UsingGlobal());
-        ui->volume_slider->setEnabled(Settings::values.volume.UsingGlobal());
-        return;
-    }
-
-    ConfigurationShared::SetColoredComboBox(ui->combo_sound, ui->mode_label,
-                                            Settings::values.sound_index.GetValue(true));
-
-    connect(ui->volume_combo_box, qOverload<int>(&QComboBox::activated), this, [this](int index) {
-        ui->volume_slider->setEnabled(index == 1);
-        ConfigurationShared::SetHighlight(ui->volume_layout, index == 1);
-    });
-
-    ui->sink_combo_box->setVisible(false);
-    ui->sink_label->setVisible(false);
-    ui->output_combo_box->setVisible(false);
-    ui->output_label->setVisible(false);
-    ui->input_combo_box->setVisible(false);
-    ui->input_label->setVisible(false);
 }
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index 0d03aae1df..79538e81c6 100644
--- a/src/yuzu/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
@@ -3,30 +3,35 @@
 
 #pragma once
 
+#include <functional>
 #include <memory>
+#include <vector>
 #include <QWidget>
+#include "yuzu/configuration/configuration_shared.h"
+
+class QComboBox;
 
 namespace Core {
 class System;
 }
 
-namespace ConfigurationShared {
-enum class CheckState;
-}
-
 namespace Ui {
 class ConfigureAudio;
 }
 
-class ConfigureAudio : public QWidget {
-    Q_OBJECT
+namespace ConfigurationShared {
+class Builder;
+}
 
+class ConfigureAudio : public ConfigurationShared::Tab {
 public:
-    explicit ConfigureAudio(const Core::System& system_, QWidget* parent = nullptr);
+    explicit ConfigureAudio(const Core::System& system_,
+                            std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
+                            const ConfigurationShared::Builder& builder, QWidget* parent = nullptr);
     ~ConfigureAudio() override;
 
-    void ApplyConfiguration();
-    void SetConfiguration();
+    void ApplyConfiguration() override;
+    void SetConfiguration() override;
 
 private:
     void changeEvent(QEvent* event) override;
@@ -39,11 +44,16 @@ private:
 
     void SetOutputSinkFromSinkID();
     void SetAudioDevicesFromDeviceID();
-    void SetVolumeIndicatorText(int percentage);
 
-    void SetupPerGameUI();
+    void Setup(const ConfigurationShared::Builder& builder);
 
     std::unique_ptr<Ui::ConfigureAudio> ui;
 
     const Core::System& system;
+
+    std::vector<std::function<void(bool)>> apply_funcs{};
+
+    QComboBox* sink_combo_box;
+    QComboBox* output_device_combo_box;
+    QComboBox* input_device_combo_box;
 };
diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui
index 4128c83ad4..1181aeb007 100644
--- a/src/yuzu/configuration/configure_audio.ui
+++ b/src/yuzu/configuration/configure_audio.ui
@@ -21,80 +21,14 @@
      </property>
      <layout class="QVBoxLayout">
       <item>
-       <layout class="QHBoxLayout" name="engine_layout">
-        <item>
-         <widget class="QLabel" name="sink_label">
-          <property name="text">
-           <string>Output Engine:</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QComboBox" name="sink_combo_box"/>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="output_layout">
-        <item>
-         <widget class="QLabel" name="output_label">
-          <property name="text">
-           <string>Output Device:</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QComboBox" name="output_combo_box"/>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="input_layout">
-        <item>
-         <widget class="QLabel" name="input_label">
-          <property name="text">
-           <string>Input Device:</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QComboBox" name="input_combo_box"/>
-        </item>
-       </layout>
-      </item>
-       <item>
-       <layout class="QHBoxLayout" name="mode_layout">
-        <item>
-         <widget class="QLabel" name="mode_label">
-          <property name="text">
-           <string>Sound Output Mode:</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-          <widget class="QComboBox" name="combo_sound">
-            <item>
-              <property name="text">
-                <string>Mono</string>
-              </property>
-            </item>
-            <item>
-              <property name="text">
-                <string>Stereo</string>
-              </property>
-            </item>
-            <item>
-              <property name="text">
-                <string>Surround</string>
-              </property>
-            </item>
-          </widget>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <widget class="QWidget" name="volume_layout" native="true">
-        <layout class="QHBoxLayout" name="horizontalLayout_2">
+       <widget class="QWidget" name="audio_widget" native="true">
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>16777213</height>
+         </size>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout">
          <property name="leftMargin">
           <number>0</number>
          </property>
@@ -107,89 +41,9 @@
          <property name="bottomMargin">
           <number>0</number>
          </property>
-         <item>
-          <widget class="QComboBox" name="volume_combo_box">
-           <item>
-            <property name="text">
-             <string>Use global volume</string>
-            </property>
-           </item>
-           <item>
-            <property name="text">
-             <string>Set volume:</string>
-            </property>
-           </item>
-          </widget>
-         </item>
-         <item>
-          <widget class="QLabel" name="volume_label">
-           <property name="text">
-            <string>Volume:</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <spacer name="horizontalSpacer">
-           <property name="orientation">
-            <enum>Qt::Horizontal</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>30</width>
-             <height>20</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-         <item>
-          <widget class="QSlider" name="volume_slider">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="maximum">
-            <number>200</number>
-           </property>
-           <property name="pageStep">
-            <number>5</number>
-           </property>
-           <property name="orientation">
-            <enum>Qt::Horizontal</enum>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QLabel" name="volume_indicator">
-           <property name="minimumSize">
-            <size>
-             <width>32</width>
-             <height>0</height>
-            </size>
-           </property>
-           <property name="text">
-            <string>0 %</string>
-           </property>
-           <property name="alignment">
-            <set>Qt::AlignCenter</set>
-           </property>
-          </widget>
-         </item>
         </layout>
        </widget>
       </item>
-      <item>
-       <layout class="QHBoxLayout" name="mute_layout">
-         <item>
-           <widget class="QCheckBox" name="toggle_background_mute">
-             <property name="text">
-               <string>Mute audio when in background</string>
-             </property>
-           </widget>
-         </item>
-       </layout>
-      </item>
      </layout>
     </widget>
    </item>
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
index 3d69fb03ff..a513599038 100644
--- a/src/yuzu/configuration/configure_cpu.cpp
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -1,88 +1,92 @@
 // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
+#include <memory>
+#include <typeinfo>
+#include <vector>
+#include <QComboBox>
 #include "common/common_types.h"
 #include "common/settings.h"
+#include "common/settings_enums.h"
+#include "configuration/shared_widget.h"
 #include "core/core.h"
 #include "ui_configure_cpu.h"
 #include "yuzu/configuration/configuration_shared.h"
 #include "yuzu/configuration/configure_cpu.h"
 
-ConfigureCpu::ConfigureCpu(const Core::System& system_, QWidget* parent)
-    : QWidget(parent), ui{std::make_unique<Ui::ConfigureCpu>()}, system{system_} {
+ConfigureCpu::ConfigureCpu(const Core::System& system_,
+                           std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
+                           const ConfigurationShared::Builder& builder, QWidget* parent)
+    : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureCpu>()}, system{system_},
+      combobox_translations(builder.ComboboxTranslations()) {
     ui->setupUi(this);
 
-    SetupPerGameUI();
+    Setup(builder);
 
     SetConfiguration();
 
-    connect(ui->accuracy, qOverload<int>(&QComboBox::currentIndexChanged), this,
+    connect(accuracy_combobox, qOverload<int>(&QComboBox::currentIndexChanged), this,
             &ConfigureCpu::UpdateGroup);
 }
 
 ConfigureCpu::~ConfigureCpu() = default;
 
-void ConfigureCpu::SetConfiguration() {
-    const bool runtime_lock = !system.IsPoweredOn();
+void ConfigureCpu::SetConfiguration() {}
+void ConfigureCpu::Setup(const ConfigurationShared::Builder& builder) {
+    auto* accuracy_layout = ui->widget_accuracy->layout();
+    auto* unsafe_layout = ui->unsafe_widget->layout();
+    std::map<u32, QWidget*> unsafe_hold{};
 
-    ui->accuracy->setEnabled(runtime_lock);
-    ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock);
-    ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock);
-    ui->cpuopt_unsafe_ignore_standard_fpcr->setEnabled(runtime_lock);
-    ui->cpuopt_unsafe_inaccurate_nan->setEnabled(runtime_lock);
-    ui->cpuopt_unsafe_fastmem_check->setEnabled(runtime_lock);
-    ui->cpuopt_unsafe_ignore_global_monitor->setEnabled(runtime_lock);
+    std::vector<Settings::BasicSetting*> settings;
+    const auto push = [&](Settings::Category category) {
+        for (const auto setting : Settings::values.linkage.by_category[category]) {
+            settings.push_back(setting);
+        }
+    };
 
-    ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma.GetValue());
-    ui->cpuopt_unsafe_reduce_fp_error->setChecked(
-        Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue());
-    ui->cpuopt_unsafe_ignore_standard_fpcr->setChecked(
-        Settings::values.cpuopt_unsafe_ignore_standard_fpcr.GetValue());
-    ui->cpuopt_unsafe_inaccurate_nan->setChecked(
-        Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue());
-    ui->cpuopt_unsafe_fastmem_check->setChecked(
-        Settings::values.cpuopt_unsafe_fastmem_check.GetValue());
-    ui->cpuopt_unsafe_ignore_global_monitor->setChecked(
-        Settings::values.cpuopt_unsafe_ignore_global_monitor.GetValue());
+    push(Settings::Category::Cpu);
+    push(Settings::Category::CpuUnsafe);
 
-    if (Settings::IsConfiguringGlobal()) {
-        ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy.GetValue()));
-    } else {
-        ConfigurationShared::SetPerGameSetting(ui->accuracy, &Settings::values.cpu_accuracy);
-        ConfigurationShared::SetHighlight(ui->widget_accuracy,
-                                          !Settings::values.cpu_accuracy.UsingGlobal());
+    for (const auto setting : settings) {
+        auto* widget = builder.BuildWidget(setting, apply_funcs);
+
+        if (widget == nullptr) {
+            continue;
+        }
+        if (!widget->Valid()) {
+            widget->deleteLater();
+            continue;
+        }
+
+        if (setting->Id() == Settings::values.cpu_accuracy.Id()) {
+            // Keep track of cpu_accuracy combobox to display/hide the unsafe settings
+            accuracy_layout->addWidget(widget);
+            accuracy_combobox = widget->combobox;
+        } else {
+            // Presently, all other settings here are unsafe checkboxes
+            unsafe_hold.insert({setting->Id(), widget});
+        }
     }
-    UpdateGroup(ui->accuracy->currentIndex());
+
+    for (const auto& [label, widget] : unsafe_hold) {
+        unsafe_layout->addWidget(widget);
+    }
+
+    UpdateGroup(accuracy_combobox->currentIndex());
 }
 
 void ConfigureCpu::UpdateGroup(int index) {
-    if (!Settings::IsConfiguringGlobal()) {
-        index -= ConfigurationShared::USE_GLOBAL_OFFSET;
-    }
-    const auto accuracy = static_cast<Settings::CPUAccuracy>(index);
-    ui->unsafe_group->setVisible(accuracy == Settings::CPUAccuracy::Unsafe);
+    const auto accuracy = static_cast<Settings::CpuAccuracy>(
+        combobox_translations.at(Settings::EnumMetadata<Settings::CpuAccuracy>::Index())[index]
+            .first);
+    ui->unsafe_group->setVisible(accuracy == Settings::CpuAccuracy::Unsafe);
 }
 
 void ConfigureCpu::ApplyConfiguration() {
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpu_accuracy, ui->accuracy);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_unfuse_fma,
-                                             ui->cpuopt_unsafe_unfuse_fma,
-                                             cpuopt_unsafe_unfuse_fma);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_reduce_fp_error,
-                                             ui->cpuopt_unsafe_reduce_fp_error,
-                                             cpuopt_unsafe_reduce_fp_error);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_ignore_standard_fpcr,
-                                             ui->cpuopt_unsafe_ignore_standard_fpcr,
-                                             cpuopt_unsafe_ignore_standard_fpcr);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_inaccurate_nan,
-                                             ui->cpuopt_unsafe_inaccurate_nan,
-                                             cpuopt_unsafe_inaccurate_nan);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_fastmem_check,
-                                             ui->cpuopt_unsafe_fastmem_check,
-                                             cpuopt_unsafe_fastmem_check);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_ignore_global_monitor,
-                                             ui->cpuopt_unsafe_ignore_global_monitor,
-                                             cpuopt_unsafe_ignore_global_monitor);
+    const bool is_powered_on = system.IsPoweredOn();
+    for (const auto& apply_func : apply_funcs) {
+        apply_func(is_powered_on);
+    }
 }
 
 void ConfigureCpu::changeEvent(QEvent* event) {
@@ -96,32 +100,3 @@ void ConfigureCpu::changeEvent(QEvent* event) {
 void ConfigureCpu::RetranslateUI() {
     ui->retranslateUi(this);
 }
-
-void ConfigureCpu::SetupPerGameUI() {
-    if (Settings::IsConfiguringGlobal()) {
-        return;
-    }
-
-    ConfigurationShared::SetColoredComboBox(
-        ui->accuracy, ui->widget_accuracy,
-        static_cast<u32>(Settings::values.cpu_accuracy.GetValue(true)));
-
-    ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_unfuse_fma,
-                                            Settings::values.cpuopt_unsafe_unfuse_fma,
-                                            cpuopt_unsafe_unfuse_fma);
-    ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_reduce_fp_error,
-                                            Settings::values.cpuopt_unsafe_reduce_fp_error,
-                                            cpuopt_unsafe_reduce_fp_error);
-    ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_ignore_standard_fpcr,
-                                            Settings::values.cpuopt_unsafe_ignore_standard_fpcr,
-                                            cpuopt_unsafe_ignore_standard_fpcr);
-    ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_inaccurate_nan,
-                                            Settings::values.cpuopt_unsafe_inaccurate_nan,
-                                            cpuopt_unsafe_inaccurate_nan);
-    ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_fastmem_check,
-                                            Settings::values.cpuopt_unsafe_fastmem_check,
-                                            cpuopt_unsafe_fastmem_check);
-    ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_ignore_global_monitor,
-                                            Settings::values.cpuopt_unsafe_ignore_global_monitor,
-                                            cpuopt_unsafe_ignore_global_monitor);
-}
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h
index 86d928ca3b..61a6de7aa7 100644
--- a/src/yuzu/configuration/configure_cpu.h
+++ b/src/yuzu/configuration/configure_cpu.h
@@ -4,29 +4,34 @@
 #pragma once
 
 #include <memory>
+#include <vector>
 #include <QWidget>
+#include "yuzu/configuration/configuration_shared.h"
+#include "yuzu/configuration/shared_translation.h"
+
+class QComboBox;
 
 namespace Core {
 class System;
 }
 
-namespace ConfigurationShared {
-enum class CheckState;
-}
-
 namespace Ui {
 class ConfigureCpu;
 }
 
-class ConfigureCpu : public QWidget {
-    Q_OBJECT
+namespace ConfigurationShared {
+class Builder;
+}
 
+class ConfigureCpu : public ConfigurationShared::Tab {
 public:
-    explicit ConfigureCpu(const Core::System& system_, QWidget* parent = nullptr);
+    explicit ConfigureCpu(const Core::System& system_,
+                          std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
+                          const ConfigurationShared::Builder& builder, QWidget* parent = nullptr);
     ~ConfigureCpu() override;
 
-    void ApplyConfiguration();
-    void SetConfiguration();
+    void ApplyConfiguration() override;
+    void SetConfiguration() override;
 
 private:
     void changeEvent(QEvent* event) override;
@@ -34,16 +39,14 @@ private:
 
     void UpdateGroup(int index);
 
-    void SetupPerGameUI();
+    void Setup(const ConfigurationShared::Builder& builder);
 
     std::unique_ptr<Ui::ConfigureCpu> ui;
 
-    ConfigurationShared::CheckState cpuopt_unsafe_unfuse_fma;
-    ConfigurationShared::CheckState cpuopt_unsafe_reduce_fp_error;
-    ConfigurationShared::CheckState cpuopt_unsafe_ignore_standard_fpcr;
-    ConfigurationShared::CheckState cpuopt_unsafe_inaccurate_nan;
-    ConfigurationShared::CheckState cpuopt_unsafe_fastmem_check;
-    ConfigurationShared::CheckState cpuopt_unsafe_ignore_global_monitor;
-
     const Core::System& system;
+
+    const ConfigurationShared::ComboboxTranslationMap& combobox_translations;
+    std::vector<std::function<void(bool)>> apply_funcs{};
+
+    QComboBox* accuracy_combobox;
 };
diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui
index 8ae569ee67..f734e842e8 100644
--- a/src/yuzu/configuration/configure_cpu.ui
+++ b/src/yuzu/configuration/configure_cpu.ui
@@ -16,9 +16,12 @@
   <property name="accessibleName">
    <string>CPU</string>
   </property>
-  <layout class="QVBoxLayout">
+  <layout class="QVBoxLayout" name="vboxlayout_2" stretch="0">
    <item>
-    <layout class="QVBoxLayout">
+    <layout class="QVBoxLayout" name="vboxlayout">
+     <property name="bottomMargin">
+      <number>0</number>
+     </property>
      <item>
       <widget class="QGroupBox" name="groupBox">
        <property name="title">
@@ -27,38 +30,19 @@
        <layout class="QVBoxLayout">
         <item>
          <widget class="QWidget" name="widget_accuracy" native="true">
-          <layout class="QHBoxLayout" name="layout_accuracy">
-           <item>
-            <widget class="QLabel" name="label_accuracy">
-             <property name="text">
-              <string>Accuracy:</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QComboBox" name="accuracy">
-             <item>
-              <property name="text">
-               <string>Auto</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Accurate</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Unsafe</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Paranoid (disables most optimizations)</string>
-              </property>
-             </item>
-            </widget>
-           </item>
+          <layout class="QVBoxLayout" name="verticalLayout">
+           <property name="leftMargin">
+            <number>0</number>
+           </property>
+           <property name="topMargin">
+            <number>0</number>
+           </property>
+           <property name="rightMargin">
+            <number>0</number>
+           </property>
+           <property name="bottomMargin">
+            <number>0</number>
+           </property>
           </layout>
          </widget>
         </item>
@@ -75,10 +59,6 @@
        </layout>
       </widget>
      </item>
-    </layout>
-   </item>
-   <item>
-    <layout class="QVBoxLayout">
      <item>
       <widget class="QGroupBox" name="unsafe_group">
        <property name="title">
@@ -96,105 +76,44 @@
          </widget>
         </item>
         <item>
-         <widget class="QCheckBox" name="cpuopt_unsafe_unfuse_fma">
-          <property name="toolTip">
-           <string>
-            &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
-           </string>
-          </property>
-          <property name="text">
-           <string>Unfuse FMA (improve performance on CPUs without FMA)</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="cpuopt_unsafe_reduce_fp_error">
-          <property name="toolTip">
-           <string>
-            &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
-           </string>
-          </property>
-          <property name="text">
-           <string>Faster FRSQRTE and FRECPE</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="cpuopt_unsafe_ignore_standard_fpcr">
-          <property name="toolTip">
-           <string>
-            &lt;div&gt;This option improves the speed of 32 bits ASIMD floating-point functions by running with incorrect rounding modes.&lt;/div&gt;
-           </string>
-          </property>
-          <property name="text">
-           <string>Faster ASIMD instructions (32 bits only)</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="cpuopt_unsafe_inaccurate_nan">
-          <property name="toolTip">
-           <string>
-            &lt;div&gt;This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.&lt;/div&gt;
-           </string>
-          </property>
-          <property name="text">
-           <string>Inaccurate NaN handling</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="cpuopt_unsafe_fastmem_check">
-          <property name="toolTip">
-           <string>
-            &lt;div&gt;This option improves speed by eliminating a safety check before every memory read/write in guest. Disabling it may allow a game to read/write the emulator's memory.&lt;/div&gt;
-           </string>
-          </property>
-          <property name="text">
-           <string>Disable address space checks</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="cpuopt_unsafe_ignore_global_monitor">
-          <property name="toolTip">
-           <string>
-            &lt;div&gt;This option improves speed by relying only on the semantics of cmpxchg to ensure safety of exclusive access instructions. Please note this may result in deadlocks and other race conditions.&lt;/div&gt;
-           </string>
-          </property>
-          <property name="text">
-           <string>Ignore global monitor</string>
-          </property>
+         <widget class="QWidget" name="unsafe_widget" native="true">
+          <layout class="QVBoxLayout" name="unsafe_layout">
+           <property name="leftMargin">
+            <number>0</number>
+           </property>
+           <property name="topMargin">
+            <number>0</number>
+           </property>
+           <property name="rightMargin">
+            <number>0</number>
+           </property>
+           <property name="bottomMargin">
+            <number>0</number>
+           </property>
+          </layout>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
+     <item>
+      <spacer name="verticalSpacer">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+       <property name="sizeType">
+        <enum>QSizePolicy::Expanding</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>20</width>
+         <height>40</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
     </layout>
    </item>
-   <item>
-    <spacer name="verticalSpacer">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>40</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item>
-    <widget class="QLabel" name="label_disable_info">
-     <property name="text">
-      <string>CPU settings are available only when game is not running.</string>
-     </property>
-     <property name="wordWrap">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
   </layout>
  </widget>
  <resources/>
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 15acefe332..97c7d9022e 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -2,360 +2,549 @@
 <ui version="4.0">
  <class>ConfigureDebug</class>
  <widget class="QScrollArea" name="ConfigureDebug">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>831</width>
+    <height>760</height>
+   </rect>
+  </property>
   <property name="widgetResizable">
    <bool>true</bool>
   </property>
- <widget class="QWidget">
-  <layout class="QVBoxLayout" name="verticalLayout_1">
-   <item>
-    <layout class="QVBoxLayout" name="verticalLayout_2">
-     <item>
-      <widget class="QGroupBox" name="groupBox">
-       <property name="title">
-        <string>Debugger</string>
-       </property>
-       <layout class="QVBoxLayout" name="verticalLayout_3">
-        <item>
-         <layout class="QHBoxLayout" name="horizontalLayout_11">
-          <item>
-           <widget class="QCheckBox" name="toggle_gdbstub">
-            <property name="text">
-             <string>Enable GDB Stub</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <spacer name="horizontalSpacer">
-            <property name="orientation">
-             <enum>Qt::Horizontal</enum>
-            </property>
-            <property name="sizeHint" stdset="0">
-             <size>
-              <width>40</width>
-              <height>20</height>
-             </size>
-            </property>
-           </spacer>
-          </item>
-          <item>
-           <widget class="QLabel" name="label_11">
-            <property name="text">
-             <string>Port:</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="QSpinBox" name="gdbport_spinbox">
-            <property name="minimum">
-             <number>1024</number>
-            </property>
-            <property name="maximum">
-             <number>65535</number>
-            </property>
-           </widget>
-          </item>
-         </layout>
-        </item>
-       </layout>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item>
-    <widget class="QGroupBox" name="groupBox_2">
-     <property name="title">
-      <string>Logging</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_1">
-      <item row="0" column="0" colspan="2">
-       <layout class="QHBoxLayout" name="horizontalLayout_1">
-        <item>
-         <widget class="QLabel" name="label_1">
-          <property name="text">
-           <string>Global Log Filter</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QLineEdit" name="log_filter_edit"/>
-        </item>
-       </layout>
-      </item>
-      <item row="1" column="0">
-       <widget class="QCheckBox" name="toggle_console">
-        <property name="text">
-         <string>Show Log in Console</string>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="1">
-       <widget class="QPushButton" name="open_log_button">
-        <property name="text">
-         <string>Open Log Location</string>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="0">
-       <widget class="QCheckBox" name="extended_logging">
-        <property name="enabled">
-         <bool>true</bool>
-        </property>
-        <property name="toolTip">
-         <string>When checked, the max size of the log increases from 100 MB to 1 GB</string>
-        </property>
-        <property name="text">
-         <string>Enable Extended Logging**</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item>
-    <widget class="QGroupBox" name="groupBox_3">
-     <property name="title">
-      <string>Homebrew</string>
-     </property>
-     <layout class="QVBoxLayout" name="verticalLayout_5">
+  <widget class="QWidget" name="widget">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>829</width>
+     <height>758</height>
+    </rect>
+   </property>
+   <layout class="QVBoxLayout" name="verticalLayout_1">
+    <item>
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="topMargin">
+       <number>0</number>
+      </property>
       <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_4">
-        <item>
-         <widget class="QLabel" name="label_3">
-          <property name="text">
-           <string>Arguments String</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QLineEdit" name="homebrew_args_edit"/>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item>
-    <widget class="QGroupBox" name="groupBox_4">
-     <property name="title">
-      <string>Graphics</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_2">
-      <item row="0" column="0">
-       <widget class="QCheckBox" name="enable_graphics_debugging">
-        <property name="enabled">
-         <bool>true</bool>
+       <widget class="QGroupBox" name="groupBox">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
         </property>
-        <property name="toolTip">
-         <string>When checked, the graphics API enters a slower debugging mode</string>
+        <property name="title">
+         <string>Debugger</string>
         </property>
-        <property name="text">
-         <string>Enable Graphics Debugging</string>
+        <property name="alignment">
+         <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
         </property>
+        <property name="flat">
+         <bool>false</bool>
+        </property>
+        <property name="checkable">
+         <bool>false</bool>
+        </property>
+        <layout class="QVBoxLayout" name="verticalLayout_3">
+         <item>
+          <widget class="QWidget" name="debug_widget" native="true">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <layout class="QVBoxLayout" name="verticalLayout">
+            <property name="sizeConstraint">
+             <enum>QLayout::SetDefaultConstraint</enum>
+            </property>
+            <property name="leftMargin">
+             <number>0</number>
+            </property>
+            <property name="topMargin">
+             <number>0</number>
+            </property>
+            <property name="rightMargin">
+             <number>0</number>
+            </property>
+            <property name="bottomMargin">
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QCheckBox" name="toggle_gdbstub">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="text">
+               <string>Enable GDB Stub</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QWidget" name="horizontalWidget_3" native="true">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <layout class="QHBoxLayout" name="horizontalLayout_3">
+               <property name="leftMargin">
+                <number>0</number>
+               </property>
+               <property name="topMargin">
+                <number>0</number>
+               </property>
+               <property name="rightMargin">
+                <number>0</number>
+               </property>
+               <property name="bottomMargin">
+                <number>0</number>
+               </property>
+               <item>
+                <widget class="QLabel" name="label_11">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="text">
+                  <string>Port:</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QSpinBox" name="gdbport_spinbox">
+                 <property name="sizePolicy">
+                  <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+                   <horstretch>0</horstretch>
+                   <verstretch>0</verstretch>
+                  </sizepolicy>
+                 </property>
+                 <property name="minimum">
+                  <number>1024</number>
+                 </property>
+                 <property name="maximum">
+                  <number>65535</number>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
        </widget>
       </item>
-      <item row="2" column="0">
-       <widget class="QCheckBox" name="enable_nsight_aftermath">
-        <property name="toolTip">
-         <string>When checked, it enables Nsight Aftermath crash dumps</string>
+      <item>
+       <widget class="QGroupBox" name="groupBox_2">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
         </property>
-        <property name="text">
-         <string>Enable Nsight Aftermath</string>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="1">
-       <widget class="QCheckBox" name="dump_shaders">
-        <property name="enabled">
-         <bool>true</bool>
-        </property>
-        <property name="toolTip">
-         <string>When checked, it will dump all the original assembler shaders from the disk shader cache or game as found</string>
-        </property>
-        <property name="text">
-         <string>Dump Game Shaders</string>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="2">
-       <widget class="QCheckBox" name="dump_macros">
-        <property name="enabled">
-         <bool>true</bool>
-        </property>
-        <property name="toolTip">
-         <string>When checked, it will dump all the macro programs of the GPU</string>
-        </property>
-        <property name="text">
-         <string>Dump Maxwell Macros</string>
-        </property>
-       </widget>
-      </item>
-      <item row="0" column="1">
-       <widget class="QCheckBox" name="disable_macro_jit">
-        <property name="enabled">
-         <bool>true</bool>
-        </property>
-        <property name="toolTip">
-         <string>When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower</string>
-        </property>
-        <property name="text">
-         <string>Disable Macro JIT</string>
-        </property>
-       </widget>
-      </item>
-      <item row="0" column="2">
-       <widget class="QCheckBox" name="disable_macro_hle">
-        <property name="enabled">
-         <bool>true</bool>
-        </property>
-        <property name="toolTip">
-         <string>When checked, it disables the macro HLE functions. Enabling this makes games run slower</string>
-        </property>
-        <property name="text">
-         <string>Disable Macro HLE</string>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="0">
-       <widget class="QCheckBox" name="enable_shader_feedback">
-        <property name="toolTip">
-         <string>When checked, yuzu will log statistics about the compiled pipeline cache</string>
-        </property>
-        <property name="text">
-         <string>Enable Shader Feedback</string>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="1">
-       <widget class="QCheckBox" name="disable_loop_safety_checks">
-        <property name="toolTip">
-         <string>When checked, it executes shaders without loop logic changes</string>
-        </property>
-        <property name="text">
-         <string>Disable Loop safety checks</string>
+        <property name="title">
+         <string>Logging</string>
         </property>
+        <layout class="QGridLayout" name="gridLayout_1">
+         <item row="1" column="1">
+          <widget class="QPushButton" name="open_log_button">
+           <property name="text">
+            <string>Open Log Location</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="0" colspan="2">
+          <widget class="QWidget" name="logging_widget" native="true">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_1">
+            <property name="leftMargin">
+             <number>0</number>
+            </property>
+            <property name="topMargin">
+             <number>0</number>
+            </property>
+            <property name="rightMargin">
+             <number>0</number>
+            </property>
+            <property name="bottomMargin">
+             <number>0</number>
+            </property>
+            <item>
+             <widget class="QLabel" name="label_1">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="text">
+               <string>Global Log Filter</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QLineEdit" name="log_filter_edit"/>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item row="2" column="0">
+          <widget class="QCheckBox" name="extended_logging">
+           <property name="enabled">
+            <bool>true</bool>
+           </property>
+           <property name="toolTip">
+            <string>When checked, the max size of the log increases from 100 MB to 1 GB</string>
+           </property>
+           <property name="text">
+            <string>Enable Extended Logging**</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QCheckBox" name="toggle_console">
+           <property name="text">
+            <string>Show Log in Console</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
        </widget>
       </item>
      </layout>
-    </widget>
-   </item>
-   <item>
-    <widget class="QGroupBox" name="groupBox_5">
-     <property name="title">
-      <string>Debugging</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_3">
-      <item row="2" column="0">
-       <widget class="QCheckBox" name="reporting_services">
-        <property name="text">
-         <string>Enable Verbose Reporting Services**</string>
+    </item>
+    <item>
+     <widget class="QGroupBox" name="groupBox_3">
+      <property name="title">
+       <string>Homebrew</string>
+      </property>
+      <layout class="QVBoxLayout" name="verticalLayout_5">
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_4">
+         <item>
+          <widget class="QLabel" name="label_3">
+           <property name="text">
+            <string>Arguments String</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLineEdit" name="homebrew_args_edit"/>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </widget>
+    </item>
+    <item>
+     <layout class="QHBoxLayout" name="horizontalLayout_2">
+      <item>
+       <widget class="QGroupBox" name="groupBox_4">
+        <property name="title">
+         <string>Graphics</string>
         </property>
+        <layout class="QGridLayout" name="gridLayout_2">
+         <item row="3" column="0">
+          <widget class="QCheckBox" name="disable_loop_safety_checks">
+           <property name="toolTip">
+            <string>When checked, it executes shaders without loop logic changes</string>
+           </property>
+           <property name="text">
+            <string>Disable Loop safety checks</string>
+           </property>
+          </widget>
+         </item>
+         <item row="4" column="0">
+          <widget class="QCheckBox" name="dump_shaders">
+           <property name="enabled">
+            <bool>true</bool>
+           </property>
+           <property name="toolTip">
+            <string>When checked, it will dump all the original assembler shaders from the disk shader cache or game as found</string>
+           </property>
+           <property name="text">
+            <string>Dump Game Shaders</string>
+           </property>
+          </widget>
+         </item>
+         <item row="7" column="0">
+          <widget class="QCheckBox" name="disable_macro_hle">
+           <property name="enabled">
+            <bool>true</bool>
+           </property>
+           <property name="toolTip">
+            <string>When checked, it disables the macro HLE functions. Enabling this makes games run slower</string>
+           </property>
+           <property name="text">
+            <string>Disable Macro HLE</string>
+           </property>
+          </widget>
+         </item>
+         <item row="5" column="0">
+          <widget class="QCheckBox" name="disable_macro_jit">
+           <property name="enabled">
+            <bool>true</bool>
+           </property>
+           <property name="toolTip">
+            <string>When checked, it disables the macro Just In Time compiler. Enabling this makes games run slower</string>
+           </property>
+           <property name="text">
+            <string>Disable Macro JIT</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="0">
+          <widget class="QCheckBox" name="enable_graphics_debugging">
+           <property name="enabled">
+            <bool>true</bool>
+           </property>
+           <property name="toolTip">
+            <string>When checked, the graphics API enters a slower debugging mode</string>
+           </property>
+           <property name="text">
+            <string>Enable Graphics Debugging</string>
+           </property>
+          </widget>
+         </item>
+         <item row="6" column="0">
+          <widget class="QCheckBox" name="dump_macros">
+           <property name="enabled">
+            <bool>true</bool>
+           </property>
+           <property name="toolTip">
+            <string>When checked, it will dump all the macro programs of the GPU</string>
+           </property>
+           <property name="text">
+            <string>Dump Maxwell Macros</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QCheckBox" name="enable_shader_feedback">
+           <property name="toolTip">
+            <string>When checked, yuzu will log statistics about the compiled pipeline cache</string>
+           </property>
+           <property name="text">
+            <string>Enable Shader Feedback</string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="0">
+          <widget class="QCheckBox" name="enable_nsight_aftermath">
+           <property name="toolTip">
+            <string>When checked, it enables Nsight Aftermath crash dumps</string>
+           </property>
+           <property name="text">
+            <string>Enable Nsight Aftermath</string>
+           </property>
+          </widget>
+         </item>
+         <item row="8" column="0">
+          <spacer name="verticalSpacer_5">
+           <property name="orientation">
+            <enum>Qt::Vertical</enum>
+           </property>
+           <property name="sizeType">
+            <enum>QSizePolicy::Preferred</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>20</width>
+             <height>0</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
        </widget>
       </item>
-      <item row="0" column="0">
-       <widget class="QCheckBox" name="fs_access_log">
-        <property name="text">
-         <string>Enable FS Access Log</string>
+      <item>
+       <widget class="QGroupBox" name="groupBox_6">
+        <property name="title">
+         <string>Advanced</string>
         </property>
+        <layout class="QGridLayout" name="gridLayout_4">
+         <item row="3" column="0">
+          <widget class="QCheckBox" name="perform_vulkan_check">
+           <property name="toolTip">
+            <string>Enables yuzu to check for a working Vulkan environment when the program starts up. Disable this if this is causing issues with external programs seeing yuzu.</string>
+           </property>
+           <property name="text">
+            <string>Perform Startup Vulkan Check</string>
+           </property>
+          </widget>
+         </item>
+         <item row="4" column="0">
+          <widget class="QCheckBox" name="disable_web_applet">
+           <property name="text">
+            <string>Disable Web Applet</string>
+           </property>
+          </widget>
+         </item>
+         <item row="5" column="0">
+          <widget class="QCheckBox" name="enable_all_controllers">
+           <property name="text">
+            <string>Enable All Controller Types</string>
+           </property>
+          </widget>
+         </item>
+         <item row="6" column="0">
+          <widget class="QCheckBox" name="use_auto_stub">
+           <property name="text">
+            <string>Enable Auto-Stub**</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="0">
+          <widget class="QCheckBox" name="quest_flag">
+           <property name="text">
+            <string>Kiosk (Quest) Mode</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QCheckBox" name="enable_cpu_debugging">
+           <property name="text">
+            <string>Enable CPU Debugging</string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="0">
+          <widget class="QCheckBox" name="use_debug_asserts">
+           <property name="text">
+            <string>Enable Debug Asserts</string>
+           </property>
+          </widget>
+         </item>
+         <item row="7" column="0">
+          <spacer name="verticalSpacer_4">
+           <property name="orientation">
+            <enum>Qt::Vertical</enum>
+           </property>
+           <property name="sizeType">
+            <enum>QSizePolicy::Expanding</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>20</width>
+             <height>0</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
        </widget>
       </item>
-      <item row="0" column="1">
-       <widget class="QCheckBox" name="dump_audio_commands">
-        <property name="toolTip">
-         <string>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</string>
-        </property>
-        <property name="text">
-         <string>Dump Audio Commands To Console**</string>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="1">
-       <widget class="QCheckBox" name="create_crash_dumps">
-        <property name="text">
-         <string>Create Minidump After Crash</string>
+      <item>
+       <widget class="QGroupBox" name="groupBox_5">
+        <property name="title">
+         <string>Debugging</string>
         </property>
+        <layout class="QGridLayout" name="gridLayout_3">
+         <item row="0" column="0">
+          <widget class="QCheckBox" name="fs_access_log">
+           <property name="text">
+            <string>Enable FS Access Log</string>
+           </property>
+          </widget>
+         </item>
+         <item row="4" column="0">
+          <widget class="QCheckBox" name="create_crash_dumps">
+           <property name="text">
+            <string>Create Minidump After Crash</string>
+           </property>
+          </widget>
+         </item>
+         <item row="3" column="0">
+          <widget class="QCheckBox" name="dump_audio_commands">
+           <property name="toolTip">
+            <string>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</string>
+           </property>
+           <property name="text">
+            <string>Dump Audio Commands To Console**</string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="0">
+          <widget class="QCheckBox" name="reporting_services">
+           <property name="text">
+            <string>Enable Verbose Reporting Services**</string>
+           </property>
+          </widget>
+         </item>
+         <item row="5" column="0">
+          <spacer name="verticalSpacer_3">
+           <property name="orientation">
+            <enum>Qt::Vertical</enum>
+           </property>
+           <property name="sizeType">
+            <enum>QSizePolicy::Expanding</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>20</width>
+             <height>0</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
        </widget>
       </item>
      </layout>
-    </widget>
-   </item>
-   <item>
-    <widget class="QGroupBox" name="groupBox_6">
-     <property name="title">
-      <string>Advanced</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout_4">
-      <item row="0" column="0">
-       <widget class="QCheckBox" name="quest_flag">
-        <property name="text">
-         <string>Kiosk (Quest) Mode</string>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="0">
-       <widget class="QCheckBox" name="enable_cpu_debugging">
-        <property name="text">
-         <string>Enable CPU Debugging</string>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="0">
-       <widget class="QCheckBox" name="use_debug_asserts">
-        <property name="text">
-         <string>Enable Debug Asserts</string>
-        </property>
-       </widget>
-      </item>
-      <item row="0" column="1">
-       <widget class="QCheckBox" name="use_auto_stub">
-        <property name="text">
-         <string>Enable Auto-Stub**</string>
-        </property>
-       </widget>
-      </item>
-      <item row="1" column="1">
-       <widget class="QCheckBox" name="enable_all_controllers">
-        <property name="text">
-         <string>Enable All Controller Types</string>
-        </property>
-       </widget>
-      </item>
-      <item row="2" column="1">
-       <widget class="QCheckBox" name="disable_web_applet">
-        <property name="text">
-         <string>Disable Web Applet</string>
-        </property>
-       </widget>
-      </item>
-      <item row="3" column="0">
-       <widget class="QCheckBox" name="perform_vulkan_check">
-        <property name="toolTip">
-         <string>Enables yuzu to check for a working Vulkan environment when the program starts up. Disable this if this is causing issues with external programs seeing yuzu.</string>
-        </property>
-        <property name="text">
-         <string>Perform Startup Vulkan Check</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item>
-    <widget class="QLabel" name="label_5">
-     <property name="font">
-      <font>
-       <italic>true</italic>
-      </font>
-     </property>
-     <property name="text">
-      <string>**This will be reset automatically when yuzu closes.</string>
-     </property>
-     <property name="indent">
-      <number>20</number>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
+    </item>
+    <item>
+     <spacer name="verticalSpacer">
+      <property name="orientation">
+       <enum>Qt::Vertical</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>20</width>
+        <height>0</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+    <item>
+     <widget class="QLabel" name="label_5">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="font">
+       <font>
+        <italic>true</italic>
+       </font>
+      </property>
+      <property name="text">
+       <string>**This will be reset automatically when yuzu closes.</string>
+      </property>
+      <property name="indent">
+       <number>20</number>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
  </widget>
  <tabstops>
   <tabstop>log_filter_edit</tabstop>
@@ -366,14 +555,11 @@
   <tabstop>enable_graphics_debugging</tabstop>
   <tabstop>enable_shader_feedback</tabstop>
   <tabstop>enable_nsight_aftermath</tabstop>
-  <tabstop>disable_macro_jit</tabstop>
-  <tabstop>disable_loop_safety_checks</tabstop>
   <tabstop>fs_access_log</tabstop>
   <tabstop>reporting_services</tabstop>
   <tabstop>quest_flag</tabstop>
   <tabstop>enable_cpu_debugging</tabstop>
   <tabstop>use_debug_asserts</tabstop>
-  <tabstop>use_auto_stub</tabstop>
  </tabstops>
  <resources/>
  <connections/>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index bdf83ebfe3..3c6bb3eb1a 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -32,21 +32,23 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
                                  std::vector<VkDeviceInfo::Record>& vk_device_records,
                                  Core::System& system_, bool enable_web_config)
     : QDialog(parent), ui{std::make_unique<Ui::ConfigureDialog>()},
-      registry(registry_), system{system_}, audio_tab{std::make_unique<ConfigureAudio>(system_,
-                                                                                       this)},
-      cpu_tab{std::make_unique<ConfigureCpu>(system_, this)},
+      registry(registry_), system{system_}, builder{std::make_unique<ConfigurationShared::Builder>(
+                                                this, !system_.IsPoweredOn())},
+      audio_tab{std::make_unique<ConfigureAudio>(system_, nullptr, *builder, this)},
+      cpu_tab{std::make_unique<ConfigureCpu>(system_, nullptr, *builder, this)},
       debug_tab_tab{std::make_unique<ConfigureDebugTab>(system_, this)},
       filesystem_tab{std::make_unique<ConfigureFilesystem>(this)},
-      general_tab{std::make_unique<ConfigureGeneral>(system_, this)},
-      graphics_advanced_tab{std::make_unique<ConfigureGraphicsAdvanced>(system_, this)},
+      general_tab{std::make_unique<ConfigureGeneral>(system_, nullptr, *builder, this)},
+      graphics_advanced_tab{
+          std::make_unique<ConfigureGraphicsAdvanced>(system_, nullptr, *builder, this)},
       graphics_tab{std::make_unique<ConfigureGraphics>(
           system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
-          this)},
+          nullptr, *builder, this)},
       hotkeys_tab{std::make_unique<ConfigureHotkeys>(system_.HIDCore(), this)},
       input_tab{std::make_unique<ConfigureInput>(system_, this)},
       network_tab{std::make_unique<ConfigureNetwork>(system_, this)},
       profile_tab{std::make_unique<ConfigureProfileManager>(system_, this)},
-      system_tab{std::make_unique<ConfigureSystem>(system_, this)},
+      system_tab{std::make_unique<ConfigureSystem>(system_, nullptr, *builder, this)},
       ui_tab{std::make_unique<ConfigureUi>(system_, this)}, web_tab{std::make_unique<ConfigureWeb>(
                                                                 this)} {
     Settings::SetConfiguringGlobal(true);
@@ -95,6 +97,9 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
 
     adjustSize();
     ui->selectorList->setCurrentRow(0);
+
+    // Selects the leftmost button on the bottom bar (Cancel as of writing)
+    ui->buttonBox->setFocus();
 }
 
 ConfigureDialog::~ConfigureDialog() = default;
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index 2a08b7feec..96e9a8c3e5 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -6,6 +6,9 @@
 #include <memory>
 #include <vector>
 #include <QDialog>
+#include "configuration/shared_widget.h"
+#include "yuzu/configuration/configuration_shared.h"
+#include "yuzu/configuration/shared_translation.h"
 #include "yuzu/vk_device_info.h"
 
 namespace Core {
@@ -69,6 +72,8 @@ private:
     HotkeyRegistry& registry;
 
     Core::System& system;
+    std::unique_ptr<ConfigurationShared::Builder> builder;
+    std::vector<ConfigurationShared::Tab*> tab_group;
 
     std::unique_ptr<ConfigureAudio> audio_tab;
     std::unique_ptr<ConfigureCpu> cpu_tab;
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 2f55159f5d..c727fadd1e 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -3,57 +3,60 @@
 
 #include <functional>
 #include <utility>
+#include <vector>
 #include <QMessageBox>
 #include "common/settings.h"
 #include "core/core.h"
 #include "ui_configure_general.h"
 #include "yuzu/configuration/configuration_shared.h"
 #include "yuzu/configuration/configure_general.h"
+#include "yuzu/configuration/shared_widget.h"
 #include "yuzu/uisettings.h"
 
-ConfigureGeneral::ConfigureGeneral(const Core::System& system_, QWidget* parent)
-    : QWidget(parent), ui{std::make_unique<Ui::ConfigureGeneral>()}, system{system_} {
+ConfigureGeneral::ConfigureGeneral(const Core::System& system_,
+                                   std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
+                                   const ConfigurationShared::Builder& builder, QWidget* parent)
+    : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGeneral>()}, system{system_} {
     ui->setupUi(this);
 
-    SetupPerGameUI();
+    Setup(builder);
 
     SetConfiguration();
 
-    if (Settings::IsConfiguringGlobal()) {
-        connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit,
-                [this]() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked()); });
-    }
-
     connect(ui->button_reset_defaults, &QPushButton::clicked, this,
             &ConfigureGeneral::ResetDefaults);
+
+    if (!Settings::IsConfiguringGlobal()) {
+        ui->button_reset_defaults->setVisible(false);
+    }
 }
 
 ConfigureGeneral::~ConfigureGeneral() = default;
 
-void ConfigureGeneral::SetConfiguration() {
-    const bool runtime_lock = !system.IsPoweredOn();
+void ConfigureGeneral::SetConfiguration() {}
 
-    ui->use_multi_core->setEnabled(runtime_lock);
-    ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
+void ConfigureGeneral::Setup(const ConfigurationShared::Builder& builder) {
+    QLayout& layout = *ui->general_widget->layout();
 
-    ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
-    ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue());
-    ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue());
-    ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
-    ui->toggle_controller_applet_disabled->setEnabled(runtime_lock);
-    ui->toggle_controller_applet_disabled->setChecked(
-        UISettings::values.controller_applet_disabled.GetValue());
+    std::map<u32, QWidget*> hold{};
 
-    ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue());
-    ui->speed_limit->setValue(Settings::values.speed_limit.GetValue());
+    for (const auto setting :
+         UISettings::values.linkage.by_category[Settings::Category::UiGeneral]) {
+        auto* widget = builder.BuildWidget(setting, apply_funcs);
 
-    ui->button_reset_defaults->setEnabled(runtime_lock);
+        if (widget == nullptr) {
+            continue;
+        }
+        if (!widget->Valid()) {
+            widget->deleteLater();
+            continue;
+        }
 
-    if (Settings::IsConfiguringGlobal()) {
-        ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue());
-    } else {
-        ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() &&
-                                    use_speed_limit != ConfigurationShared::CheckState::Global);
+        hold.emplace(setting->Id(), widget);
+    }
+
+    for (const auto& [id, widget] : hold) {
+        layout.addWidget(widget);
     }
 }
 
@@ -77,32 +80,9 @@ void ConfigureGeneral::ResetDefaults() {
 }
 
 void ConfigureGeneral::ApplyConfiguration() {
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core,
-                                             use_multi_core);
-
-    if (Settings::IsConfiguringGlobal()) {
-        UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
-        UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
-        UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
-        UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
-        UISettings::values.controller_applet_disabled =
-            ui->toggle_controller_applet_disabled->isChecked();
-
-        // Guard if during game and set to game-specific value
-        if (Settings::values.use_speed_limit.UsingGlobal()) {
-            Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() ==
-                                                      Qt::Checked);
-            Settings::values.speed_limit.SetValue(ui->speed_limit->value());
-        }
-    } else {
-        bool global_speed_limit = use_speed_limit == ConfigurationShared::CheckState::Global;
-        Settings::values.use_speed_limit.SetGlobal(global_speed_limit);
-        Settings::values.speed_limit.SetGlobal(global_speed_limit);
-        if (!global_speed_limit) {
-            Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() ==
-                                                      Qt::Checked);
-            Settings::values.speed_limit.SetValue(ui->speed_limit->value());
-        }
+    bool powered_on = system.IsPoweredOn();
+    for (const auto& func : apply_funcs) {
+        func(powered_on);
     }
 }
 
@@ -117,33 +97,3 @@ void ConfigureGeneral::changeEvent(QEvent* event) {
 void ConfigureGeneral::RetranslateUI() {
     ui->retranslateUi(this);
 }
-
-void ConfigureGeneral::SetupPerGameUI() {
-    if (Settings::IsConfiguringGlobal()) {
-        // Disables each setting if:
-        //  - A game is running (thus settings in use), and
-        //  - A non-global setting is applied.
-        ui->toggle_speed_limit->setEnabled(Settings::values.use_speed_limit.UsingGlobal());
-        ui->speed_limit->setEnabled(Settings::values.speed_limit.UsingGlobal());
-
-        return;
-    }
-
-    ui->toggle_check_exit->setVisible(false);
-    ui->toggle_user_on_boot->setVisible(false);
-    ui->toggle_background_pause->setVisible(false);
-    ui->toggle_hide_mouse->setVisible(false);
-    ui->toggle_controller_applet_disabled->setVisible(false);
-
-    ui->button_reset_defaults->setVisible(false);
-
-    ConfigurationShared::SetColoredTristate(ui->toggle_speed_limit,
-                                            Settings::values.use_speed_limit, use_speed_limit);
-    ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core,
-                                            use_multi_core);
-
-    connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() {
-        ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() &&
-                                    (use_speed_limit != ConfigurationShared::CheckState::Global));
-    });
-}
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index 7ff63f4253..2d953f6793 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -5,48 +5,49 @@
 
 #include <functional>
 #include <memory>
+#include <vector>
 #include <QWidget>
+#include "yuzu/configuration/configuration_shared.h"
 
 namespace Core {
 class System;
 }
 
 class ConfigureDialog;
-
-namespace ConfigurationShared {
-enum class CheckState;
-}
-
 class HotkeyRegistry;
 
 namespace Ui {
 class ConfigureGeneral;
 }
 
-class ConfigureGeneral : public QWidget {
-    Q_OBJECT
+namespace ConfigurationShared {
+class Builder;
+}
 
+class ConfigureGeneral : public ConfigurationShared::Tab {
 public:
-    explicit ConfigureGeneral(const Core::System& system_, QWidget* parent = nullptr);
+    explicit ConfigureGeneral(const Core::System& system_,
+                              std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
+                              const ConfigurationShared::Builder& builder,
+                              QWidget* parent = nullptr);
     ~ConfigureGeneral() override;
 
     void SetResetCallback(std::function<void()> callback);
     void ResetDefaults();
-    void ApplyConfiguration();
-    void SetConfiguration();
+    void ApplyConfiguration() override;
+    void SetConfiguration() override;
 
 private:
+    void Setup(const ConfigurationShared::Builder& builder);
+
     void changeEvent(QEvent* event) override;
     void RetranslateUI();
 
-    void SetupPerGameUI();
-
     std::function<void()> reset_callback;
 
     std::unique_ptr<Ui::ConfigureGeneral> ui;
 
-    ConfigurationShared::CheckState use_speed_limit;
-    ConfigurationShared::CheckState use_multi_core;
+    std::vector<std::function<void(bool)>> apply_funcs{};
 
     const Core::System& system;
 };
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index fe757d011e..a10e7d3a50 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -26,77 +26,22 @@
        </property>
        <layout class="QHBoxLayout" name="GeneralHorizontalLayout">
         <item>
-         <layout class="QVBoxLayout" name="GeneralVerticalLayout">
-          <item>
-           <layout class="QHBoxLayout" name="horizontalLayout_2">
-            <item>
-             <widget class="QCheckBox" name="toggle_speed_limit">
-              <property name="text">
-               <string>Limit Speed Percent</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QSpinBox" name="speed_limit">
-              <property name="suffix">
-               <string>%</string>
-              </property>
-              <property name="minimum">
-               <number>1</number>
-              </property>
-              <property name="maximum">
-               <number>9999</number>
-              </property>
-              <property name="value">
-               <number>100</number>
-              </property>
-             </widget>
-            </item>
-           </layout>
-          </item>
-          <item>
-           <widget class="QCheckBox" name="use_multi_core">
-            <property name="text">
-             <string>Multicore CPU Emulation</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="QCheckBox" name="toggle_check_exit">
-            <property name="text">
-             <string>Confirm exit while emulation is running</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="QCheckBox" name="toggle_user_on_boot">
-            <property name="text">
-             <string>Prompt for user on game boot</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="QCheckBox" name="toggle_background_pause">
-            <property name="text">
-             <string>Pause emulation when in background</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="QCheckBox" name="toggle_hide_mouse">
-            <property name="text">
-             <string>Hide mouse on inactivity</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="QCheckBox" name="toggle_controller_applet_disabled">
-            <property name="text">
-             <string>Disable controller applet</string>
-            </property>
-           </widget>
-          </item>
-         </layout>
+         <widget class="QWidget" name="general_widget" native="true">
+          <layout class="QVBoxLayout" name="GeneralVerticalLayout">
+           <property name="leftMargin">
+            <number>0</number>
+           </property>
+           <property name="topMargin">
+            <number>0</number>
+           </property>
+           <property name="rightMargin">
+            <number>0</number>
+           </property>
+           <property name="bottomMargin">
+            <number>0</number>
+           </property>
+          </layout>
+         </widget>
         </item>
        </layout>
       </widget>
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index a4965524ab..a94fbc89a4 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -7,6 +7,7 @@
 #include <iterator>
 #include <string>
 #include <tuple>
+#include <typeinfo>
 #include <utility>
 #include <vector>
 #include <QBoxLayout>
@@ -15,23 +16,29 @@
 #include <QComboBox>
 #include <QIcon>
 #include <QLabel>
+#include <QLineEdit>
 #include <QPixmap>
 #include <QPushButton>
 #include <QSlider>
 #include <QStringLiteral>
 #include <QtCore/qobjectdefs.h>
+#include <qabstractbutton.h>
+#include <qboxlayout.h>
 #include <qcoreevent.h>
 #include <qglobal.h>
+#include <qgridlayout.h>
 #include <vulkan/vulkan_core.h>
 
 #include "common/common_types.h"
 #include "common/dynamic_library.h"
 #include "common/logging/log.h"
 #include "common/settings.h"
+#include "common/settings_enums.h"
 #include "core/core.h"
 #include "ui_configure_graphics.h"
 #include "yuzu/configuration/configuration_shared.h"
 #include "yuzu/configuration/configure_graphics.h"
+#include "yuzu/configuration/shared_widget.h"
 #include "yuzu/qt_common.h"
 #include "yuzu/uisettings.h"
 #include "yuzu/vk_device_info.h"
@@ -46,9 +53,9 @@ static constexpr VkPresentModeKHR VSyncSettingToMode(Settings::VSyncMode mode) {
         return VK_PRESENT_MODE_IMMEDIATE_KHR;
     case Settings::VSyncMode::Mailbox:
         return VK_PRESENT_MODE_MAILBOX_KHR;
-    case Settings::VSyncMode::FIFO:
+    case Settings::VSyncMode::Fifo:
         return VK_PRESENT_MODE_FIFO_KHR;
-    case Settings::VSyncMode::FIFORelaxed:
+    case Settings::VSyncMode::FifoRelaxed:
         return VK_PRESENT_MODE_FIFO_RELAXED_KHR;
     default:
         return VK_PRESENT_MODE_FIFO_KHR;
@@ -62,50 +69,67 @@ static constexpr Settings::VSyncMode PresentModeToSetting(VkPresentModeKHR mode)
     case VK_PRESENT_MODE_MAILBOX_KHR:
         return Settings::VSyncMode::Mailbox;
     case VK_PRESENT_MODE_FIFO_KHR:
-        return Settings::VSyncMode::FIFO;
+        return Settings::VSyncMode::Fifo;
     case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
-        return Settings::VSyncMode::FIFORelaxed;
+        return Settings::VSyncMode::FifoRelaxed;
     default:
-        return Settings::VSyncMode::FIFO;
+        return Settings::VSyncMode::Fifo;
     }
 }
 
 ConfigureGraphics::ConfigureGraphics(const Core::System& system_,
                                      std::vector<VkDeviceInfo::Record>& records_,
                                      const std::function<void()>& expose_compute_option_,
-                                     QWidget* parent)
-    : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, records{records_},
-      expose_compute_option{expose_compute_option_}, system{system_} {
+                                     std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
+                                     const ConfigurationShared::Builder& builder, QWidget* parent)
+    : ConfigurationShared::Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGraphics>()},
+      records{records_}, expose_compute_option{expose_compute_option_}, system{system_},
+      combobox_translations{builder.ComboboxTranslations()},
+      shader_mapping{
+          combobox_translations.at(Settings::EnumMetadata<Settings::ShaderBackend>::Index())} {
     vulkan_device = Settings::values.vulkan_device.GetValue();
     RetrieveVulkanDevices();
 
     ui->setupUi(this);
 
+    Setup(builder);
+
     for (const auto& device : vulkan_devices) {
-        ui->device->addItem(device);
+        vulkan_device_combobox->addItem(device);
     }
 
-    ui->backend->addItem(QStringLiteral("GLSL"));
-    ui->backend->addItem(tr("GLASM (Assembly Shaders, NVIDIA Only)"));
-    ui->backend->addItem(tr("SPIR-V (Experimental, Mesa Only)"));
+    UpdateBackgroundColorButton(QColor::fromRgb(Settings::values.bg_red.GetValue(),
+                                                Settings::values.bg_green.GetValue(),
+                                                Settings::values.bg_blue.GetValue()));
+    UpdateAPILayout();
+    PopulateVSyncModeSelection(); //< must happen after UpdateAPILayout
 
-    SetupPerGameUI();
+    // VSync setting needs to be determined after populating the VSync combobox
+    if (Settings::IsConfiguringGlobal()) {
+        const auto vsync_mode_setting = Settings::values.vsync_mode.GetValue();
+        const auto vsync_mode = VSyncSettingToMode(vsync_mode_setting);
+        int index{};
+        for (const auto mode : vsync_mode_combobox_enum_map) {
+            if (mode == vsync_mode) {
+                break;
+            }
+            index++;
+        }
+        if (static_cast<unsigned long>(index) < vsync_mode_combobox_enum_map.size()) {
+            vsync_mode_combobox->setCurrentIndex(index);
+        }
+    }
 
-    SetConfiguration();
-
-    connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] {
+    connect(api_combobox, qOverload<int>(&QComboBox::activated), this, [this] {
         UpdateAPILayout();
         PopulateVSyncModeSelection();
-        if (!Settings::IsConfiguringGlobal()) {
-            ConfigurationShared::SetHighlight(
-                ui->api_widget, ui->api->currentIndex() != ConfigurationShared::USE_GLOBAL_INDEX);
-        }
     });
-    connect(ui->device, qOverload<int>(&QComboBox::activated), this, [this](int device) {
-        UpdateDeviceSelection(device);
-        PopulateVSyncModeSelection();
-    });
-    connect(ui->backend, qOverload<int>(&QComboBox::activated), this,
+    connect(vulkan_device_combobox, qOverload<int>(&QComboBox::activated), this,
+            [this](int device) {
+                UpdateDeviceSelection(device);
+                PopulateVSyncModeSelection();
+            });
+    connect(shader_backend_combobox, qOverload<int>(&QComboBox::activated), this,
             [this](int backend) { UpdateShaderBackendSelection(backend); });
 
     connect(ui->bg_button, &QPushButton::clicked, this, [this] {
@@ -116,39 +140,45 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_,
         UpdateBackgroundColorButton(new_bg_color);
     });
 
-    ui->api->setEnabled(!UISettings::values.has_broken_vulkan && ui->api->isEnabled());
+    api_combobox->setEnabled(!UISettings::values.has_broken_vulkan && api_combobox->isEnabled());
     ui->api_widget->setEnabled(
         (!UISettings::values.has_broken_vulkan || Settings::IsConfiguringGlobal()) &&
         ui->api_widget->isEnabled());
-    ui->bg_label->setVisible(Settings::IsConfiguringGlobal());
-    ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal());
 
-    connect(ui->fsr_sharpening_slider, &QSlider::valueChanged, this,
-            &ConfigureGraphics::SetFSRIndicatorText);
-    ui->fsr_sharpening_combobox->setVisible(!Settings::IsConfiguringGlobal());
-    ui->fsr_sharpening_label->setVisible(Settings::IsConfiguringGlobal());
+    if (Settings::IsConfiguringGlobal()) {
+        ui->bg_widget->setEnabled(Settings::values.bg_red.UsingGlobal());
+    }
 }
 
 void ConfigureGraphics::PopulateVSyncModeSelection() {
-    const Settings::RendererBackend backend{GetCurrentGraphicsBackend()};
-    if (backend == Settings::RendererBackend::Null) {
-        ui->vsync_mode_combobox->setEnabled(false);
+    if (!Settings::IsConfiguringGlobal()) {
         return;
     }
-    ui->vsync_mode_combobox->setEnabled(true);
+
+    const Settings::RendererBackend backend{GetCurrentGraphicsBackend()};
+    if (backend == Settings::RendererBackend::Null) {
+        vsync_mode_combobox->setEnabled(false);
+        return;
+    }
+    vsync_mode_combobox->setEnabled(true);
 
     const int current_index = //< current selected vsync mode from combobox
-        ui->vsync_mode_combobox->currentIndex();
+        vsync_mode_combobox->currentIndex();
     const auto current_mode = //< current selected vsync mode as a VkPresentModeKHR
         current_index == -1 ? VSyncSettingToMode(Settings::values.vsync_mode.GetValue())
                             : vsync_mode_combobox_enum_map[current_index];
     int index{};
-    const int device{ui->device->currentIndex()}; //< current selected Vulkan device
+    const int device{vulkan_device_combobox->currentIndex()}; //< current selected Vulkan device
+    if (device == -1) {
+        // Invalid device
+        return;
+    }
+
     const auto& present_modes = //< relevant vector of present modes for the selected device or API
         backend == Settings::RendererBackend::Vulkan ? device_present_modes[device]
                                                      : default_present_modes;
 
-    ui->vsync_mode_combobox->clear();
+    vsync_mode_combobox->clear();
     vsync_mode_combobox_enum_map.clear();
     vsync_mode_combobox_enum_map.reserve(present_modes.size());
     for (const auto present_mode : present_modes) {
@@ -157,10 +187,10 @@ void ConfigureGraphics::PopulateVSyncModeSelection() {
             continue;
         }
 
-        ui->vsync_mode_combobox->insertItem(index, mode_name);
+        vsync_mode_combobox->insertItem(index, mode_name);
         vsync_mode_combobox_enum_map.push_back(present_mode);
         if (present_mode == current_mode) {
-            ui->vsync_mode_combobox->setCurrentIndex(index);
+            vsync_mode_combobox->setCurrentIndex(index);
         }
         index++;
     }
@@ -186,112 +216,124 @@ void ConfigureGraphics::UpdateShaderBackendSelection(int backend) {
 
 ConfigureGraphics::~ConfigureGraphics() = default;
 
-void ConfigureGraphics::SetConfiguration() {
-    const bool runtime_lock = !system.IsPoweredOn();
+void ConfigureGraphics::SetConfiguration() {}
 
-    ui->api_widget->setEnabled(runtime_lock);
-    ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock);
-    ui->use_disk_shader_cache->setEnabled(runtime_lock);
-    ui->nvdec_emulation_widget->setEnabled(runtime_lock);
-    ui->resolution_combobox->setEnabled(runtime_lock);
-    ui->accelerate_astc->setEnabled(runtime_lock);
-    ui->vsync_mode_layout->setEnabled(runtime_lock ||
-                                      Settings::values.renderer_backend.GetValue() ==
-                                          Settings::RendererBackend::Vulkan);
-    ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
-    ui->use_asynchronous_gpu_emulation->setChecked(
-        Settings::values.use_asynchronous_gpu_emulation.GetValue());
-    ui->accelerate_astc->setChecked(Settings::values.accelerate_astc.GetValue());
+void ConfigureGraphics::Setup(const ConfigurationShared::Builder& builder) {
+    QLayout* api_layout = ui->api_widget->layout();
+    QWidget* api_grid_widget = new QWidget(this);
+    QVBoxLayout* api_grid_layout = new QVBoxLayout(api_grid_widget);
+    api_grid_layout->setContentsMargins(0, 0, 0, 0);
+    api_layout->addWidget(api_grid_widget);
 
-    if (Settings::IsConfiguringGlobal()) {
-        ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
-        ui->fullscreen_mode_combobox->setCurrentIndex(
-            static_cast<int>(Settings::values.fullscreen_mode.GetValue()));
-        ui->nvdec_emulation->setCurrentIndex(
-            static_cast<int>(Settings::values.nvdec_emulation.GetValue()));
-        ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
-        ui->resolution_combobox->setCurrentIndex(
-            static_cast<int>(Settings::values.resolution_setup.GetValue()));
-        ui->scaling_filter_combobox->setCurrentIndex(
-            static_cast<int>(Settings::values.scaling_filter.GetValue()));
-        ui->fsr_sharpening_slider->setValue(Settings::values.fsr_sharpening_slider.GetValue());
-        ui->anti_aliasing_combobox->setCurrentIndex(
-            static_cast<int>(Settings::values.anti_aliasing.GetValue()));
-    } else {
-        ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
-        ConfigurationShared::SetHighlight(ui->api_widget,
-                                          !Settings::values.renderer_backend.UsingGlobal());
+    QLayout& graphics_layout = *ui->graphics_widget->layout();
 
-        ConfigurationShared::SetPerGameSetting(ui->nvdec_emulation,
-                                               &Settings::values.nvdec_emulation);
-        ConfigurationShared::SetHighlight(ui->nvdec_emulation_widget,
-                                          !Settings::values.nvdec_emulation.UsingGlobal());
+    std::map<u32, QWidget*> hold_graphics;
+    std::vector<QWidget*> hold_api;
 
-        ConfigurationShared::SetPerGameSetting(ui->fullscreen_mode_combobox,
-                                               &Settings::values.fullscreen_mode);
-        ConfigurationShared::SetHighlight(ui->fullscreen_mode_label,
-                                          !Settings::values.fullscreen_mode.UsingGlobal());
-
-        ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox,
-                                               &Settings::values.aspect_ratio);
-        ConfigurationShared::SetHighlight(ui->ar_label,
-                                          !Settings::values.aspect_ratio.UsingGlobal());
-
-        ConfigurationShared::SetPerGameSetting(ui->resolution_combobox,
-                                               &Settings::values.resolution_setup);
-        ConfigurationShared::SetHighlight(ui->resolution_label,
-                                          !Settings::values.resolution_setup.UsingGlobal());
-
-        ConfigurationShared::SetPerGameSetting(ui->scaling_filter_combobox,
-                                               &Settings::values.scaling_filter);
-        ConfigurationShared::SetHighlight(ui->scaling_filter_label,
-                                          !Settings::values.scaling_filter.UsingGlobal());
-
-        ConfigurationShared::SetPerGameSetting(ui->anti_aliasing_combobox,
-                                               &Settings::values.anti_aliasing);
-        ConfigurationShared::SetHighlight(ui->anti_aliasing_label,
-                                          !Settings::values.anti_aliasing.UsingGlobal());
-
-        ui->fsr_sharpening_combobox->setCurrentIndex(
-            Settings::values.fsr_sharpening_slider.UsingGlobal() ? 0 : 1);
-        ui->fsr_sharpening_slider->setEnabled(
-            !Settings::values.fsr_sharpening_slider.UsingGlobal());
-        ui->fsr_sharpening_value->setEnabled(!Settings::values.fsr_sharpening_slider.UsingGlobal());
-        ConfigurationShared::SetHighlight(ui->fsr_sharpening_layout,
-                                          !Settings::values.fsr_sharpening_slider.UsingGlobal());
-        ui->fsr_sharpening_slider->setValue(Settings::values.fsr_sharpening_slider.GetValue());
-
-        ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
-        ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
-        ConfigurationShared::SetHighlight(ui->bg_layout, !Settings::values.bg_red.UsingGlobal());
-    }
-    UpdateBackgroundColorButton(QColor::fromRgb(Settings::values.bg_red.GetValue(),
-                                                Settings::values.bg_green.GetValue(),
-                                                Settings::values.bg_blue.GetValue()));
-    UpdateAPILayout();
-    PopulateVSyncModeSelection(); //< must happen after UpdateAPILayout
-    SetFSRIndicatorText(ui->fsr_sharpening_slider->sliderPosition());
-
-    // VSync setting needs to be determined after populating the VSync combobox
-    if (Settings::IsConfiguringGlobal()) {
-        const auto vsync_mode_setting = Settings::values.vsync_mode.GetValue();
-        const auto vsync_mode = VSyncSettingToMode(vsync_mode_setting);
-        int index{};
-        for (const auto mode : vsync_mode_combobox_enum_map) {
-            if (mode == vsync_mode) {
-                break;
+    for (const auto setting : Settings::values.linkage.by_category[Settings::Category::Renderer]) {
+        ConfigurationShared::Widget* widget = [&]() {
+            if (setting->Id() == Settings::values.fsr_sharpening_slider.Id()) {
+                // FSR needs a reversed slider and a 0.5 multiplier
+                return builder.BuildWidget(
+                    setting, apply_funcs, ConfigurationShared::RequestType::ReverseSlider, true,
+                    0.5f, nullptr, tr("%", "FSR sharpening percentage (e.g. 50%)"));
+            } else {
+                return builder.BuildWidget(setting, apply_funcs);
             }
-            index++;
+        }();
+
+        if (widget == nullptr) {
+            continue;
         }
-        if (static_cast<unsigned long>(index) < vsync_mode_combobox_enum_map.size()) {
-            ui->vsync_mode_combobox->setCurrentIndex(index);
+        if (!widget->Valid()) {
+            widget->deleteLater();
+            continue;
+        }
+
+        if (setting->Id() == Settings::values.renderer_backend.Id()) {
+            // Add the renderer combobox now so it's at the top
+            api_grid_layout->addWidget(widget);
+            api_combobox = widget->combobox;
+            api_restore_global_button = widget->restore_button;
+
+            if (!Settings::IsConfiguringGlobal()) {
+                QObject::connect(api_restore_global_button, &QAbstractButton::clicked,
+                                 [this](bool) { UpdateAPILayout(); });
+
+                // Detach API's restore button and place it where we want
+                // Lets us put it on the side, and it will automatically scale if there's a
+                // second combobox (shader_backend, vulkan_device)
+                widget->layout()->removeWidget(api_restore_global_button);
+                api_layout->addWidget(api_restore_global_button);
+            }
+        } else if (setting->Id() == Settings::values.vulkan_device.Id()) {
+            // Keep track of vulkan_device's combobox so we can populate it
+            hold_api.push_back(widget);
+            vulkan_device_combobox = widget->combobox;
+            vulkan_device_widget = widget;
+        } else if (setting->Id() == Settings::values.shader_backend.Id()) {
+            // Keep track of shader_backend's combobox so we can populate it
+            hold_api.push_back(widget);
+            shader_backend_combobox = widget->combobox;
+            shader_backend_widget = widget;
+        } else if (setting->Id() == Settings::values.vsync_mode.Id()) {
+            // Keep track of vsync_mode's combobox so we can populate it
+            vsync_mode_combobox = widget->combobox;
+            hold_graphics.emplace(setting->Id(), widget);
+        } else {
+            hold_graphics.emplace(setting->Id(), widget);
         }
     }
-}
 
-void ConfigureGraphics::SetFSRIndicatorText(int percentage) {
-    ui->fsr_sharpening_value->setText(
-        tr("%1%", "FSR sharpening percentage (e.g. 50%)").arg(100 - (percentage / 2)));
+    for (const auto& [id, widget] : hold_graphics) {
+        graphics_layout.addWidget(widget);
+    }
+
+    for (auto widget : hold_api) {
+        api_grid_layout->addWidget(widget);
+    }
+
+    // Background color is too specific to build into the new system, so we manage it here
+    // (3 settings, all collected into a single widget with a QColor to manage on top)
+    if (Settings::IsConfiguringGlobal()) {
+        apply_funcs.push_back([this](bool powered_on) {
+            Settings::values.bg_red.SetValue(static_cast<u8>(bg_color.red()));
+            Settings::values.bg_green.SetValue(static_cast<u8>(bg_color.green()));
+            Settings::values.bg_blue.SetValue(static_cast<u8>(bg_color.blue()));
+        });
+    } else {
+        QPushButton* bg_restore_button = ConfigurationShared::Widget::CreateRestoreGlobalButton(
+            Settings::values.bg_red.UsingGlobal(), ui->bg_widget);
+        ui->bg_widget->layout()->addWidget(bg_restore_button);
+
+        QObject::connect(bg_restore_button, &QAbstractButton::clicked,
+                         [bg_restore_button, this](bool) {
+                             const int r = Settings::values.bg_red.GetValue(true);
+                             const int g = Settings::values.bg_green.GetValue(true);
+                             const int b = Settings::values.bg_blue.GetValue(true);
+                             UpdateBackgroundColorButton(QColor::fromRgb(r, g, b));
+
+                             bg_restore_button->setVisible(false);
+                             bg_restore_button->setEnabled(false);
+                         });
+
+        QObject::connect(ui->bg_button, &QAbstractButton::clicked, [bg_restore_button](bool) {
+            bg_restore_button->setVisible(true);
+            bg_restore_button->setEnabled(true);
+        });
+
+        apply_funcs.push_back([bg_restore_button, this](bool powered_on) {
+            const bool using_global = !bg_restore_button->isEnabled();
+            Settings::values.bg_red.SetGlobal(using_global);
+            Settings::values.bg_green.SetGlobal(using_global);
+            Settings::values.bg_blue.SetGlobal(using_global);
+            if (!using_global) {
+                Settings::values.bg_red.SetValue(static_cast<u8>(bg_color.red()));
+                Settings::values.bg_green.SetValue(static_cast<u8>(bg_color.green()));
+                Settings::values.bg_blue.SetValue(static_cast<u8>(bg_color.blue()));
+            }
+        });
+    }
 }
 
 const QString ConfigureGraphics::TranslateVSyncMode(VkPresentModeKHR mode,
@@ -315,130 +357,48 @@ const QString ConfigureGraphics::TranslateVSyncMode(VkPresentModeKHR mode,
     }
 }
 
+int ConfigureGraphics::FindIndex(u32 enumeration, int value) const {
+    for (u32 i = 0; i < combobox_translations.at(enumeration).size(); i++) {
+        if (combobox_translations.at(enumeration)[i].first == static_cast<u32>(value)) {
+            return i;
+        }
+    }
+    return -1;
+}
+
 void ConfigureGraphics::ApplyConfiguration() {
-    const auto resolution_setup = static_cast<Settings::ResolutionSetup>(
-        ui->resolution_combobox->currentIndex() -
-        ((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
-
-    const auto scaling_filter = static_cast<Settings::ScalingFilter>(
-        ui->scaling_filter_combobox->currentIndex() -
-        ((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
-
-    const auto anti_aliasing = static_cast<Settings::AntiAliasing>(
-        ui->anti_aliasing_combobox->currentIndex() -
-        ((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
-
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.fullscreen_mode,
-                                             ui->fullscreen_mode_combobox);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
-                                             ui->aspect_ratio_combobox);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
-                                             ui->use_disk_shader_cache, use_disk_shader_cache);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
-                                             ui->use_asynchronous_gpu_emulation,
-                                             use_asynchronous_gpu_emulation);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.accelerate_astc, ui->accelerate_astc,
-                                             accelerate_astc);
+    const bool powered_on = system.IsPoweredOn();
+    for (const auto& func : apply_funcs) {
+        func(powered_on);
+    }
 
     if (Settings::IsConfiguringGlobal()) {
-        // Guard if during game and set to game-specific value
-        if (Settings::values.renderer_backend.UsingGlobal()) {
-            Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
-        }
-        if (Settings::values.nvdec_emulation.UsingGlobal()) {
-            Settings::values.nvdec_emulation.SetValue(GetCurrentNvdecEmulation());
-        }
-        if (Settings::values.shader_backend.UsingGlobal()) {
-            Settings::values.shader_backend.SetValue(shader_backend);
-        }
-        if (Settings::values.vulkan_device.UsingGlobal()) {
-            Settings::values.vulkan_device.SetValue(vulkan_device);
-        }
-        if (Settings::values.bg_red.UsingGlobal()) {
-            Settings::values.bg_red.SetValue(static_cast<u8>(bg_color.red()));
-            Settings::values.bg_green.SetValue(static_cast<u8>(bg_color.green()));
-            Settings::values.bg_blue.SetValue(static_cast<u8>(bg_color.blue()));
-        }
-        if (Settings::values.resolution_setup.UsingGlobal()) {
-            Settings::values.resolution_setup.SetValue(resolution_setup);
-        }
-        if (Settings::values.scaling_filter.UsingGlobal()) {
-            Settings::values.scaling_filter.SetValue(scaling_filter);
-        }
-        if (Settings::values.anti_aliasing.UsingGlobal()) {
-            Settings::values.anti_aliasing.SetValue(anti_aliasing);
-        }
-        Settings::values.fsr_sharpening_slider.SetValue(ui->fsr_sharpening_slider->value());
-
-        const auto mode = vsync_mode_combobox_enum_map[ui->vsync_mode_combobox->currentIndex()];
+        const auto mode = vsync_mode_combobox_enum_map[vsync_mode_combobox->currentIndex()];
         const auto vsync_mode = PresentModeToSetting(mode);
         Settings::values.vsync_mode.SetValue(vsync_mode);
-    } else {
-        if (ui->resolution_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
-            Settings::values.resolution_setup.SetGlobal(true);
-        } else {
-            Settings::values.resolution_setup.SetGlobal(false);
-            Settings::values.resolution_setup.SetValue(resolution_setup);
-        }
-        if (ui->scaling_filter_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
-            Settings::values.scaling_filter.SetGlobal(true);
-        } else {
-            Settings::values.scaling_filter.SetGlobal(false);
-            Settings::values.scaling_filter.SetValue(scaling_filter);
-        }
-        if (ui->anti_aliasing_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
-            Settings::values.anti_aliasing.SetGlobal(true);
-        } else {
-            Settings::values.anti_aliasing.SetGlobal(false);
-            Settings::values.anti_aliasing.SetValue(anti_aliasing);
-        }
-        if (ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
-            Settings::values.renderer_backend.SetGlobal(true);
-            Settings::values.shader_backend.SetGlobal(true);
-            Settings::values.vulkan_device.SetGlobal(true);
-        } else {
-            Settings::values.renderer_backend.SetGlobal(false);
-            Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
-            switch (GetCurrentGraphicsBackend()) {
-            case Settings::RendererBackend::OpenGL:
-            case Settings::RendererBackend::Null:
-                Settings::values.shader_backend.SetGlobal(false);
-                Settings::values.vulkan_device.SetGlobal(true);
-                Settings::values.shader_backend.SetValue(shader_backend);
-                break;
-            case Settings::RendererBackend::Vulkan:
-                Settings::values.shader_backend.SetGlobal(true);
-                Settings::values.vulkan_device.SetGlobal(false);
-                Settings::values.vulkan_device.SetValue(vulkan_device);
-                break;
-            }
-        }
+    }
 
-        if (ui->nvdec_emulation->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
-            Settings::values.nvdec_emulation.SetGlobal(true);
-        } else {
-            Settings::values.nvdec_emulation.SetGlobal(false);
-            Settings::values.nvdec_emulation.SetValue(GetCurrentNvdecEmulation());
-        }
-
-        if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
-            Settings::values.bg_red.SetGlobal(true);
-            Settings::values.bg_green.SetGlobal(true);
-            Settings::values.bg_blue.SetGlobal(true);
-        } else {
-            Settings::values.bg_red.SetGlobal(false);
-            Settings::values.bg_green.SetGlobal(false);
-            Settings::values.bg_blue.SetGlobal(false);
-            Settings::values.bg_red.SetValue(static_cast<u8>(bg_color.red()));
-            Settings::values.bg_green.SetValue(static_cast<u8>(bg_color.green()));
-            Settings::values.bg_blue.SetValue(static_cast<u8>(bg_color.blue()));
-        }
-
-        if (ui->fsr_sharpening_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
-            Settings::values.fsr_sharpening_slider.SetGlobal(true);
-        } else {
-            Settings::values.fsr_sharpening_slider.SetGlobal(false);
-            Settings::values.fsr_sharpening_slider.SetValue(ui->fsr_sharpening_slider->value());
+    Settings::values.vulkan_device.SetGlobal(true);
+    Settings::values.shader_backend.SetGlobal(true);
+    if (Settings::IsConfiguringGlobal() ||
+        (!Settings::IsConfiguringGlobal() && api_restore_global_button->isEnabled())) {
+        auto backend = static_cast<Settings::RendererBackend>(
+            combobox_translations
+                .at(Settings::EnumMetadata<
+                    Settings::RendererBackend>::Index())[api_combobox->currentIndex()]
+                .first);
+        switch (backend) {
+        case Settings::RendererBackend::OpenGL:
+            Settings::values.shader_backend.SetGlobal(Settings::IsConfiguringGlobal());
+            Settings::values.shader_backend.SetValue(static_cast<Settings::ShaderBackend>(
+                shader_mapping[shader_backend_combobox->currentIndex()].first));
+            break;
+        case Settings::RendererBackend::Vulkan:
+            Settings::values.vulkan_device.SetGlobal(Settings::IsConfiguringGlobal());
+            Settings::values.vulkan_device.SetValue(vulkan_device_combobox->currentIndex());
+            break;
+        case Settings::RendererBackend::Null:
+            break;
         }
     }
 }
@@ -466,36 +426,26 @@ void ConfigureGraphics::UpdateBackgroundColorButton(QColor color) {
 }
 
 void ConfigureGraphics::UpdateAPILayout() {
-    if (!Settings::IsConfiguringGlobal() &&
-        ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
-        vulkan_device = Settings::values.vulkan_device.GetValue(true);
-        shader_backend = Settings::values.shader_backend.GetValue(true);
-        ui->device_widget->setEnabled(false);
-        ui->backend_widget->setEnabled(false);
-    } else {
-        vulkan_device = Settings::values.vulkan_device.GetValue();
-        shader_backend = Settings::values.shader_backend.GetValue();
-        ui->device_widget->setEnabled(true);
-        ui->backend_widget->setEnabled(true);
-    }
+    bool runtime_lock = !system.IsPoweredOn();
+    bool need_global = !(Settings::IsConfiguringGlobal() || api_restore_global_button->isEnabled());
+    vulkan_device = Settings::values.vulkan_device.GetValue(need_global);
+    shader_backend = Settings::values.shader_backend.GetValue(need_global);
+    vulkan_device_widget->setEnabled(!need_global && runtime_lock);
+    shader_backend_widget->setEnabled(!need_global && runtime_lock);
 
-    switch (GetCurrentGraphicsBackend()) {
-    case Settings::RendererBackend::OpenGL:
-        ui->backend->setCurrentIndex(static_cast<u32>(shader_backend));
-        ui->device_widget->setVisible(false);
-        ui->backend_widget->setVisible(true);
-        break;
-    case Settings::RendererBackend::Vulkan:
-        if (static_cast<int>(vulkan_device) < ui->device->count()) {
-            ui->device->setCurrentIndex(vulkan_device);
-        }
-        ui->device_widget->setVisible(true);
-        ui->backend_widget->setVisible(false);
-        break;
-    case Settings::RendererBackend::Null:
-        ui->device_widget->setVisible(false);
-        ui->backend_widget->setVisible(false);
-        break;
+    const auto current_backend = GetCurrentGraphicsBackend();
+    const bool is_opengl = current_backend == Settings::RendererBackend::OpenGL;
+    const bool is_vulkan = current_backend == Settings::RendererBackend::Vulkan;
+
+    vulkan_device_widget->setVisible(is_vulkan);
+    shader_backend_widget->setVisible(is_opengl);
+
+    if (is_opengl) {
+        shader_backend_combobox->setCurrentIndex(
+            FindIndex(Settings::EnumMetadata<Settings::ShaderBackend>::Index(),
+                      static_cast<int>(shader_backend)));
+    } else if (is_vulkan && static_cast<int>(vulkan_device) < vulkan_device_combobox->count()) {
+        vulkan_device_combobox->setCurrentIndex(vulkan_device);
     }
 }
 
@@ -515,92 +465,11 @@ void ConfigureGraphics::RetrieveVulkanDevices() {
 }
 
 Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const {
-    if (Settings::IsConfiguringGlobal()) {
-        return static_cast<Settings::RendererBackend>(ui->api->currentIndex());
+    if (!Settings::IsConfiguringGlobal() && !api_restore_global_button->isEnabled()) {
+        return Settings::values.renderer_backend.GetValue(true);
     }
-
-    if (ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
-        Settings::values.renderer_backend.SetGlobal(true);
-        return Settings::values.renderer_backend.GetValue();
-    }
-    Settings::values.renderer_backend.SetGlobal(false);
-    return static_cast<Settings::RendererBackend>(ui->api->currentIndex() -
-                                                  ConfigurationShared::USE_GLOBAL_OFFSET);
-}
-
-Settings::NvdecEmulation ConfigureGraphics::GetCurrentNvdecEmulation() const {
-    if (Settings::IsConfiguringGlobal()) {
-        return static_cast<Settings::NvdecEmulation>(ui->nvdec_emulation->currentIndex());
-    }
-
-    if (ui->nvdec_emulation->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
-        Settings::values.nvdec_emulation.SetGlobal(true);
-        return Settings::values.nvdec_emulation.GetValue();
-    }
-    Settings::values.nvdec_emulation.SetGlobal(false);
-    return static_cast<Settings::NvdecEmulation>(ui->nvdec_emulation->currentIndex() -
-                                                 ConfigurationShared::USE_GLOBAL_OFFSET);
-}
-
-void ConfigureGraphics::SetupPerGameUI() {
-    if (Settings::IsConfiguringGlobal()) {
-        ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal());
-        ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal());
-        ui->fullscreen_mode_combobox->setEnabled(Settings::values.fullscreen_mode.UsingGlobal());
-        ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
-        ui->resolution_combobox->setEnabled(Settings::values.resolution_setup.UsingGlobal());
-        ui->scaling_filter_combobox->setEnabled(Settings::values.scaling_filter.UsingGlobal());
-        ui->fsr_sharpening_slider->setEnabled(Settings::values.fsr_sharpening_slider.UsingGlobal());
-        ui->anti_aliasing_combobox->setEnabled(Settings::values.anti_aliasing.UsingGlobal());
-        ui->use_asynchronous_gpu_emulation->setEnabled(
-            Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
-        ui->nvdec_emulation->setEnabled(Settings::values.nvdec_emulation.UsingGlobal());
-        ui->accelerate_astc->setEnabled(Settings::values.accelerate_astc.UsingGlobal());
-        ui->use_disk_shader_cache->setEnabled(Settings::values.use_disk_shader_cache.UsingGlobal());
-        ui->bg_button->setEnabled(Settings::values.bg_red.UsingGlobal());
-        ui->fsr_slider_layout->setEnabled(Settings::values.fsr_sharpening_slider.UsingGlobal());
-
-        return;
-    }
-
-    connect(ui->bg_combobox, qOverload<int>(&QComboBox::activated), this, [this](int index) {
-        ui->bg_button->setEnabled(index == 1);
-        ConfigurationShared::SetHighlight(ui->bg_layout, index == 1);
-    });
-
-    connect(ui->fsr_sharpening_combobox, qOverload<int>(&QComboBox::activated), this,
-            [this](int index) {
-                ui->fsr_sharpening_slider->setEnabled(index == 1);
-                ui->fsr_sharpening_value->setEnabled(index == 1);
-                ConfigurationShared::SetHighlight(ui->fsr_sharpening_layout, index == 1);
-            });
-
-    ConfigurationShared::SetColoredTristate(
-        ui->use_disk_shader_cache, Settings::values.use_disk_shader_cache, use_disk_shader_cache);
-    ConfigurationShared::SetColoredTristate(ui->accelerate_astc, Settings::values.accelerate_astc,
-                                            accelerate_astc);
-    ConfigurationShared::SetColoredTristate(ui->use_asynchronous_gpu_emulation,
-                                            Settings::values.use_asynchronous_gpu_emulation,
-                                            use_asynchronous_gpu_emulation);
-
-    ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label,
-                                            Settings::values.aspect_ratio.GetValue(true));
-    ConfigurationShared::SetColoredComboBox(
-        ui->fullscreen_mode_combobox, ui->fullscreen_mode_label,
-        static_cast<int>(Settings::values.fullscreen_mode.GetValue(true)));
-    ConfigurationShared::SetColoredComboBox(
-        ui->resolution_combobox, ui->resolution_label,
-        static_cast<int>(Settings::values.resolution_setup.GetValue(true)));
-    ConfigurationShared::SetColoredComboBox(
-        ui->scaling_filter_combobox, ui->scaling_filter_label,
-        static_cast<int>(Settings::values.scaling_filter.GetValue(true)));
-    ConfigurationShared::SetColoredComboBox(
-        ui->anti_aliasing_combobox, ui->anti_aliasing_label,
-        static_cast<int>(Settings::values.anti_aliasing.GetValue(true)));
-    ConfigurationShared::InsertGlobalItem(
-        ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
-    ConfigurationShared::InsertGlobalItem(
-        ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true)));
-
-    ui->vsync_mode_layout->setVisible(false);
+    return static_cast<Settings::RendererBackend>(
+        combobox_translations.at(Settings::EnumMetadata<Settings::RendererBackend>::Index())
+            .at(api_combobox->currentIndex())
+            .first);
 }
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index be9310b748..02d9b00f17 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -5,6 +5,8 @@
 
 #include <functional>
 #include <memory>
+#include <type_traits>
+#include <typeindex>
 #include <vector>
 #include <QColor>
 #include <QString>
@@ -12,10 +14,14 @@
 #include <qobjectdefs.h>
 #include <vulkan/vulkan_core.h>
 #include "common/common_types.h"
+#include "configuration/shared_translation.h"
 #include "vk_device_info.h"
+#include "yuzu/configuration/configuration_shared.h"
 
+class QPushButton;
 class QEvent;
 class QObject;
+class QComboBox;
 
 namespace Settings {
 enum class NvdecEmulation : u32;
@@ -27,31 +33,33 @@ namespace Core {
 class System;
 }
 
-namespace ConfigurationShared {
-enum class CheckState;
-}
-
 namespace Ui {
 class ConfigureGraphics;
 }
 
-class ConfigureGraphics : public QWidget {
-    Q_OBJECT
+namespace ConfigurationShared {
+class Builder;
+}
 
+class ConfigureGraphics : public ConfigurationShared::Tab {
 public:
     explicit ConfigureGraphics(const Core::System& system_,
                                std::vector<VkDeviceInfo::Record>& records,
                                const std::function<void()>& expose_compute_option_,
+                               std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
+                               const ConfigurationShared::Builder& builder,
                                QWidget* parent = nullptr);
     ~ConfigureGraphics() override;
 
-    void ApplyConfiguration();
-    void SetConfiguration();
+    void ApplyConfiguration() override;
+    void SetConfiguration() override;
 
 private:
     void changeEvent(QEvent* event) override;
     void RetranslateUI();
 
+    void Setup(const ConfigurationShared::Builder& builder);
+
     void PopulateVSyncModeSelection();
     void UpdateBackgroundColorButton(QColor color);
     void UpdateAPILayout();
@@ -60,34 +68,40 @@ private:
 
     void RetrieveVulkanDevices();
 
-    void SetFSRIndicatorText(int percentage);
     /* Turns a Vulkan present mode into a textual string for a UI
      * (and eventually for a human to read) */
     const QString TranslateVSyncMode(VkPresentModeKHR mode,
                                      Settings::RendererBackend backend) const;
 
-    void SetupPerGameUI();
-
     Settings::RendererBackend GetCurrentGraphicsBackend() const;
-    Settings::NvdecEmulation GetCurrentNvdecEmulation() const;
+
+    int FindIndex(u32 enumeration, int value) const;
 
     std::unique_ptr<Ui::ConfigureGraphics> ui;
     QColor bg_color;
 
-    ConfigurationShared::CheckState use_nvdec_emulation;
-    ConfigurationShared::CheckState accelerate_astc;
-    ConfigurationShared::CheckState use_disk_shader_cache;
-    ConfigurationShared::CheckState use_asynchronous_gpu_emulation;
+    std::vector<std::function<void(bool)>> apply_funcs{};
 
     std::vector<VkDeviceInfo::Record>& records;
     std::vector<QString> vulkan_devices;
     std::vector<std::vector<VkPresentModeKHR>> device_present_modes;
     std::vector<VkPresentModeKHR>
-        vsync_mode_combobox_enum_map; //< Keeps track of which present mode corresponds to which
-                                      // selection in the combobox
+        vsync_mode_combobox_enum_map{}; //< Keeps track of which present mode corresponds to which
+                                        // selection in the combobox
     u32 vulkan_device{};
     Settings::ShaderBackend shader_backend{};
     const std::function<void()>& expose_compute_option;
 
     const Core::System& system;
+    const ConfigurationShared::ComboboxTranslationMap& combobox_translations;
+    const std::vector<std::pair<u32, QString>>& shader_mapping;
+
+    QPushButton* api_restore_global_button;
+    QComboBox* vulkan_device_combobox;
+    QComboBox* api_combobox;
+    QComboBox* shader_backend_combobox;
+    QComboBox* vsync_mode_combobox;
+    QWidget* vulkan_device_widget;
+    QWidget* api_widget;
+    QWidget* shader_backend_widget;
 };
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 39f70e406f..d09415d702 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -27,7 +27,7 @@
        <layout class="QVBoxLayout" name="verticalLayout_3">
         <item>
          <widget class="QWidget" name="api_widget" native="true">
-          <layout class="QGridLayout" name="gridLayout">
+          <layout class="QHBoxLayout" name="horizontalLayout">
            <property name="leftMargin">
             <number>0</number>
            </property>
@@ -40,115 +40,6 @@
            <property name="bottomMargin">
             <number>0</number>
            </property>
-           <property name="horizontalSpacing">
-            <number>6</number>
-           </property>
-           <item row="4" column="0">
-            <widget class="QWidget" name="backend_widget" native="true">
-             <layout class="QHBoxLayout" name="backend_layout">
-              <property name="leftMargin">
-               <number>0</number>
-              </property>
-              <property name="topMargin">
-               <number>0</number>
-              </property>
-              <property name="rightMargin">
-               <number>0</number>
-              </property>
-              <property name="bottomMargin">
-               <number>0</number>
-              </property>
-              <item>
-               <widget class="QLabel" name="backend_label">
-                <property name="text">
-                 <string>Shader Backend:</string>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QComboBox" name="backend"/>
-              </item>
-             </layout>
-            </widget>
-           </item>
-           <item row="2" column="0">
-            <widget class="QWidget" name="device_widget" native="true">
-             <layout class="QHBoxLayout" name="device_layout">
-              <property name="leftMargin">
-               <number>0</number>
-              </property>
-              <property name="topMargin">
-               <number>0</number>
-              </property>
-              <property name="rightMargin">
-               <number>0</number>
-              </property>
-              <property name="bottomMargin">
-               <number>0</number>
-              </property>
-              <item>
-               <widget class="QLabel" name="device_label">
-                <property name="text">
-                 <string>Device:</string>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QComboBox" name="device"/>
-              </item>
-             </layout>
-            </widget>
-           </item>
-           <item row="0" column="0">
-            <widget class="QWidget" name="api_layout_2" native="true">
-             <layout class="QHBoxLayout" name="api_layout">
-              <property name="leftMargin">
-               <number>0</number>
-              </property>
-              <property name="topMargin">
-               <number>0</number>
-              </property>
-              <property name="rightMargin">
-               <number>0</number>
-              </property>
-              <property name="bottomMargin">
-               <number>0</number>
-              </property>
-              <item>
-               <widget class="QLabel" name="api_label">
-                <property name="text">
-                 <string>API:</string>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QComboBox" name="api">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
-                </property>
-                <item>
-                 <property name="text">
-                  <string notr="true">OpenGL</string>
-                 </property>
-                </item>
-                <item>
-                 <property name="text">
-                  <string notr="true">Vulkan</string>
-                 </property>
-                </item>
-                <item>
-                 <property name="text">
-                  <string>None</string>
-                 </property>
-                </item>
-               </widget>
-              </item>
-             </layout>
-            </widget>
-           </item>
           </layout>
          </widget>
         </item>
@@ -168,29 +59,8 @@
        </property>
        <layout class="QVBoxLayout" name="verticalLayout_4">
         <item>
-         <widget class="QCheckBox" name="use_disk_shader_cache">
-          <property name="text">
-           <string>Use disk pipeline cache</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="use_asynchronous_gpu_emulation">
-          <property name="text">
-           <string>Use asynchronous GPU emulation</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="accelerate_astc">
-          <property name="text">
-           <string>Accelerate ASTC texture decoding</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QWidget" name="vsync_mode_layout" native="true">
-          <layout class="QHBoxLayout" name="horizontalLayout_4">
+         <widget class="QWidget" name="graphics_widget" native="true">
+          <layout class="QVBoxLayout" name="verticalLayout">
            <property name="leftMargin">
             <number>0</number>
            </property>
@@ -203,32 +73,12 @@
            <property name="bottomMargin">
             <number>0</number>
            </property>
-           <item>
-            <widget class="QLabel" name="vsync_mode_label">
-             <property name="text">
-              <string>VSync Mode:</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QComboBox" name="vsync_mode_combobox">
-             <property name="toolTip">
-              <string>FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate.
-FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down.
-Mailbox can have lower latency than FIFO and does not tear but may drop frames.
-Immediate (no synchronization) just presents whatever is available and can exhibit tearing.</string>
-             </property>
-             <property name="currentText">
-              <string/>
-             </property>
-            </widget>
-           </item>
           </layout>
          </widget>
         </item>
         <item>
-         <widget class="QWidget" name="nvdec_emulation_widget" native="true">
-          <layout class="QHBoxLayout" name="nvdec_emulation_layout">
+         <widget class="QWidget" name="bg_widget" native="true">
+          <layout class="QHBoxLayout" name="bg_layout">
            <property name="leftMargin">
             <number>0</number>
            </property>
@@ -242,535 +92,35 @@ Immediate (no synchronization) just presents whatever is available and can exhib
             <number>0</number>
            </property>
            <item>
-            <widget class="QLabel" name="nvdec_emulation_label">
-             <property name="text">
-              <string>NVDEC emulation:</string>
+            <widget class="QLabel" name="label">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
              </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QComboBox" name="nvdec_emulation">
-             <item>
-              <property name="text">
-               <string>No Video Output</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>CPU Video Decoding</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>GPU Video Decoding (Default)</string>
-              </property>
-             </item>
-            </widget>
-           </item>
-          </layout>
-         </widget>
-        </item>
-        <item>
-         <widget class="QWidget" name="fullscreen_mode_layout" native="true">
-          <layout class="QHBoxLayout" name="horizontalLayout_1">
-           <property name="leftMargin">
-            <number>0</number>
-           </property>
-           <property name="topMargin">
-            <number>0</number>
-           </property>
-           <property name="rightMargin">
-            <number>0</number>
-           </property>
-           <property name="bottomMargin">
-            <number>0</number>
-           </property>
-           <item>
-            <widget class="QLabel" name="fullscreen_mode_label">
-             <property name="text">
-              <string>Fullscreen Mode:</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QComboBox" name="fullscreen_mode_combobox">
-             <item>
-              <property name="text">
-               <string>Borderless Windowed</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Exclusive Fullscreen</string>
-              </property>
-             </item>
-            </widget>
-           </item>
-          </layout>
-         </widget>
-        </item>
-        <item>
-         <widget class="QWidget" name="aspect_ratio_layout" native="true">
-          <layout class="QHBoxLayout" name="horizontalLayout_2">
-           <property name="leftMargin">
-            <number>0</number>
-           </property>
-           <property name="topMargin">
-            <number>0</number>
-           </property>
-           <property name="rightMargin">
-            <number>0</number>
-           </property>
-           <property name="bottomMargin">
-            <number>0</number>
-           </property>
-           <item>
-            <widget class="QLabel" name="ar_label">
-             <property name="text">
-              <string>Aspect Ratio:</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QComboBox" name="aspect_ratio_combobox">
-             <item>
-              <property name="text">
-               <string>Default (16:9)</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Force 4:3</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Force 21:9</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Force 16:10</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Stretch to Window</string>
-              </property>
-             </item>
-            </widget>
-           </item>
-          </layout>
-         </widget>
-        </item>
-        <item>
-         <widget class="QWidget" name="resolution_layout" native="true">
-          <layout class="QHBoxLayout" name="horizontalLayout_5">
-           <property name="leftMargin">
-            <number>0</number>
-           </property>
-           <property name="topMargin">
-            <number>0</number>
-           </property>
-           <property name="rightMargin">
-            <number>0</number>
-           </property>
-           <property name="bottomMargin">
-            <number>0</number>
-           </property>
-           <item>
-            <widget class="QLabel" name="resolution_label">
-             <property name="text">
-              <string>Resolution:</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QComboBox" name="resolution_combobox">
-             <item>
-              <property name="text">
-               <string>0.5X  (360p/540p) [EXPERIMENTAL]</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>0.75X (540p/810p) [EXPERIMENTAL]</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>1X (720p/1080p)</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>1.5X (1080p/1620p) [EXPERIMENTAL]</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>2X (1440p/2160p)</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>3X (2160p/3240p)</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>4X (2880p/4320p)</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>5X (3600p/5400p)</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>6X (4320p/6480p)</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>7X (5040p/7560p)</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>8X (5760p/8640p)</string>
-              </property>
-             </item>
-            </widget>
-           </item>
-          </layout>
-         </widget>
-        </item>
-        <item>
-         <widget class="QWidget" name="scaling_filter_layout" native="true">
-          <layout class="QHBoxLayout" name="horizontalLayout_6">
-           <property name="leftMargin">
-            <number>0</number>
-           </property>
-           <property name="topMargin">
-            <number>0</number>
-           </property>
-           <property name="rightMargin">
-            <number>0</number>
-           </property>
-           <property name="bottomMargin">
-            <number>0</number>
-           </property>
-           <item>
-            <widget class="QLabel" name="scaling_filter_label">
-             <property name="text">
-              <string>Window Adapting Filter:</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QComboBox" name="scaling_filter_combobox">
-             <item>
-              <property name="text">
-               <string>Nearest Neighbor</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Bilinear</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Bicubic</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Gaussian</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>ScaleForce</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>AMD FidelityFX™️ Super Resolution</string>
-              </property>
-             </item>
-            </widget>
-           </item>
-          </layout>
-         </widget>
-        </item>
-        <item>
-         <widget class="QWidget" name="anti_aliasing_layout" native="true">
-          <layout class="QHBoxLayout" name="horizontalLayout_7">
-           <property name="leftMargin">
-            <number>0</number>
-           </property>
-           <property name="topMargin">
-            <number>0</number>
-           </property>
-           <property name="rightMargin">
-            <number>0</number>
-           </property>
-           <property name="bottomMargin">
-            <number>0</number>
-           </property>
-           <item>
-            <widget class="QLabel" name="anti_aliasing_label">
-             <property name="text">
-              <string>Anti-Aliasing Method:</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QComboBox" name="anti_aliasing_combobox">
-             <item>
-              <property name="text">
-               <string>None</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>FXAA</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>SMAA</string>
-              </property>
-             </item>
-            </widget>
-           </item>
-          </layout>
-         </widget>
-        </item>
-        <item>
-         <widget class="QWidget" name="fsr_sharpening_layout" native="true">
-          <property name="enabled">
-           <bool>true</bool>
-          </property>
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <layout class="QHBoxLayout" name="horizontalLayout">
-           <property name="spacing">
-            <number>6</number>
-           </property>
-           <property name="sizeConstraint">
-            <enum>QLayout::SetDefaultConstraint</enum>
-           </property>
-           <property name="leftMargin">
-            <number>0</number>
-           </property>
-           <property name="topMargin">
-            <number>0</number>
-           </property>
-           <property name="rightMargin">
-            <number>0</number>
-           </property>
-           <property name="bottomMargin">
-            <number>0</number>
-           </property>
-           <item>
-            <layout class="QHBoxLayout" name="fsr_sharpening_label_group">
-             <property name="rightMargin">
-              <number>0</number>
-             </property>
-             <property name="bottomMargin">
-              <number>0</number>
-             </property>
-             <item>
-              <widget class="QComboBox" name="fsr_sharpening_combobox">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
-                 <horstretch>0</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-               <item>
-                <property name="text">
-                 <string>Use global FSR Sharpness</string>
-                </property>
-               </item>
-               <item>
-                <property name="text">
-                 <string>Set FSR Sharpness</string>
-                </property>
-               </item>
-              </widget>
-             </item>
-             <item>
-              <widget class="QLabel" name="fsr_sharpening_label">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                 <horstretch>0</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-               <property name="text">
-                <string>FSR Sharpness:</string>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <spacer name="horizontalSpacer_2">
-               <property name="orientation">
-                <enum>Qt::Horizontal</enum>
-               </property>
-               <property name="sizeHint" stdset="0">
-                <size>
-                 <width>40</width>
-                 <height>20</height>
-                </size>
-               </property>
-              </spacer>
-             </item>
-            </layout>
-           </item>
-           <item>
-            <layout class="QHBoxLayout" name="fsr_slider_layout">
-             <property name="spacing">
-              <number>6</number>
-             </property>
-             <item>
-              <widget class="QSlider" name="fsr_sharpening_slider">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
-                 <horstretch>0</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-               <property name="baseSize">
-                <size>
-                 <width>0</width>
-                 <height>0</height>
-                </size>
-               </property>
-               <property name="maximum">
-                <number>200</number>
-               </property>
-               <property name="sliderPosition">
-                <number>25</number>
-               </property>
-               <property name="orientation">
-                <enum>Qt::Horizontal</enum>
-               </property>
-               <property name="invertedAppearance">
-                <bool>true</bool>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QLabel" name="fsr_sharpening_value">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
-                 <horstretch>0</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-               <property name="minimumSize">
-                <size>
-                 <width>32</width>
-                 <height>0</height>
-                </size>
-               </property>
-               <property name="text">
-                <string>100%</string>
-               </property>
-               <property name="alignment">
-                <set>Qt::AlignCenter</set>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </item>
-          </layout>
-         </widget>
-        </item>
-        <item>
-         <widget class="QWidget" name="bg_layout" native="true">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <layout class="QHBoxLayout" name="horizontalLayout_3">
-           <property name="spacing">
-            <number>6</number>
-           </property>
-           <property name="leftMargin">
-            <number>0</number>
-           </property>
-           <property name="topMargin">
-            <number>0</number>
-           </property>
-           <property name="rightMargin">
-            <number>0</number>
-           </property>
-           <property name="bottomMargin">
-            <number>0</number>
-           </property>
-           <item>
-            <widget class="QComboBox" name="bg_combobox">
-             <property name="currentText">
-              <string>Use global background color</string>
-             </property>
-             <property name="currentIndex">
-              <number>0</number>
-             </property>
-             <property name="maxVisibleItems">
-              <number>10</number>
-             </property>
-             <item>
-              <property name="text">
-               <string>Use global background color</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Set background color:</string>
-              </property>
-             </item>
-            </widget>
-           </item>
-           <item>
-            <widget class="QLabel" name="bg_label">
              <property name="text">
               <string>Background Color:</string>
              </property>
             </widget>
            </item>
-           <item>
-            <spacer name="horizontalSpacer">
-             <property name="orientation">
-              <enum>Qt::Horizontal</enum>
-             </property>
-             <property name="sizeHint" stdset="0">
-              <size>
-               <width>40</width>
-               <height>20</height>
-              </size>
-             </property>
-            </spacer>
-           </item>
            <item>
             <widget class="QPushButton" name="bg_button">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
              <property name="maximumSize">
               <size>
                <width>40</width>
                <height>16777215</height>
               </size>
              </property>
+             <property name="text">
+              <string/>
+             </property>
             </widget>
            </item>
           </layout>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index c0a044767a..4db18673d4 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -1,104 +1,68 @@
 // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
+#include <vector>
+#include <QLabel>
+#include <qnamespace.h>
 #include "common/settings.h"
 #include "core/core.h"
 #include "ui_configure_graphics_advanced.h"
 #include "yuzu/configuration/configuration_shared.h"
 #include "yuzu/configuration/configure_graphics_advanced.h"
+#include "yuzu/configuration/shared_translation.h"
+#include "yuzu/configuration/shared_widget.h"
 
-ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(const Core::System& system_, QWidget* parent)
-    : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphicsAdvanced>()}, system{system_} {
+ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(
+    const Core::System& system_, std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
+    const ConfigurationShared::Builder& builder, QWidget* parent)
+    : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureGraphicsAdvanced>()}, system{system_} {
 
     ui->setupUi(this);
 
-    SetupPerGameUI();
+    Setup(builder);
 
     SetConfiguration();
 
-    ui->enable_compute_pipelines_checkbox->setVisible(false);
+    checkbox_enable_compute_pipelines->setVisible(false);
 }
 
 ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default;
 
-void ConfigureGraphicsAdvanced::SetConfiguration() {
-    const bool runtime_lock = !system.IsPoweredOn();
-    ui->use_reactive_flushing->setEnabled(runtime_lock);
-    ui->async_present->setEnabled(runtime_lock);
-    ui->renderer_force_max_clock->setEnabled(runtime_lock);
-    ui->async_astc->setEnabled(runtime_lock);
-    ui->astc_recompression_combobox->setEnabled(runtime_lock);
-    ui->use_asynchronous_shaders->setEnabled(runtime_lock);
-    ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
-    ui->enable_compute_pipelines_checkbox->setEnabled(runtime_lock);
+void ConfigureGraphicsAdvanced::SetConfiguration() {}
 
-    ui->async_present->setChecked(Settings::values.async_presentation.GetValue());
-    ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue());
-    ui->use_reactive_flushing->setChecked(Settings::values.use_reactive_flushing.GetValue());
-    ui->async_astc->setChecked(Settings::values.async_astc.GetValue());
-    ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue());
-    ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
-    ui->use_vulkan_driver_pipeline_cache->setChecked(
-        Settings::values.use_vulkan_driver_pipeline_cache.GetValue());
-    ui->enable_compute_pipelines_checkbox->setChecked(
-        Settings::values.enable_compute_pipelines.GetValue());
-    ui->use_video_framerate_checkbox->setChecked(Settings::values.use_video_framerate.GetValue());
-    ui->barrier_feedback_loops_checkbox->setChecked(
-        Settings::values.barrier_feedback_loops.GetValue());
+void ConfigureGraphicsAdvanced::Setup(const ConfigurationShared::Builder& builder) {
+    auto& layout = *ui->populate_target->layout();
+    std::map<u32, QWidget*> hold{}; // A map will sort the data for us
 
-    if (Settings::IsConfiguringGlobal()) {
-        ui->gpu_accuracy->setCurrentIndex(
-            static_cast<int>(Settings::values.gpu_accuracy.GetValue()));
-        ui->anisotropic_filtering_combobox->setCurrentIndex(
-            Settings::values.max_anisotropy.GetValue());
-        ui->astc_recompression_combobox->setCurrentIndex(
-            static_cast<int>(Settings::values.astc_recompression.GetValue()));
-    } else {
-        ConfigurationShared::SetPerGameSetting(ui->gpu_accuracy, &Settings::values.gpu_accuracy);
-        ConfigurationShared::SetPerGameSetting(ui->anisotropic_filtering_combobox,
-                                               &Settings::values.max_anisotropy);
-        ConfigurationShared::SetPerGameSetting(ui->astc_recompression_combobox,
-                                               &Settings::values.astc_recompression);
-        ConfigurationShared::SetHighlight(ui->label_gpu_accuracy,
-                                          !Settings::values.gpu_accuracy.UsingGlobal());
-        ConfigurationShared::SetHighlight(ui->af_label,
-                                          !Settings::values.max_anisotropy.UsingGlobal());
-        ConfigurationShared::SetHighlight(ui->label_astc_recompression,
-                                          !Settings::values.astc_recompression.UsingGlobal());
+    for (auto setting :
+         Settings::values.linkage.by_category[Settings::Category::RendererAdvanced]) {
+        ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs);
+
+        if (widget == nullptr) {
+            continue;
+        }
+        if (!widget->Valid()) {
+            widget->deleteLater();
+            continue;
+        }
+
+        hold.emplace(setting->Id(), widget);
+
+        // Keep track of enable_compute_pipelines so we can display it when needed
+        if (setting->Id() == Settings::values.enable_compute_pipelines.Id()) {
+            checkbox_enable_compute_pipelines = widget;
+        }
+    }
+    for (const auto& [id, widget] : hold) {
+        layout.addWidget(widget);
     }
 }
 
 void ConfigureGraphicsAdvanced::ApplyConfiguration() {
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.gpu_accuracy, ui->gpu_accuracy);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_presentation,
-                                             ui->async_present, async_present);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.renderer_force_max_clock,
-                                             ui->renderer_force_max_clock,
-                                             renderer_force_max_clock);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
-                                             ui->anisotropic_filtering_combobox);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_reactive_flushing,
-                                             ui->use_reactive_flushing, use_reactive_flushing);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_astc, ui->async_astc,
-                                             async_astc);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.astc_recompression,
-                                             ui->astc_recompression_combobox);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
-                                             ui->use_asynchronous_shaders,
-                                             use_asynchronous_shaders);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
-                                             ui->use_fast_gpu_time, use_fast_gpu_time);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vulkan_driver_pipeline_cache,
-                                             ui->use_vulkan_driver_pipeline_cache,
-                                             use_vulkan_driver_pipeline_cache);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_compute_pipelines,
-                                             ui->enable_compute_pipelines_checkbox,
-                                             enable_compute_pipelines);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_video_framerate,
-                                             ui->use_video_framerate_checkbox, use_video_framerate);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.barrier_feedback_loops,
-                                             ui->barrier_feedback_loops_checkbox,
-                                             barrier_feedback_loops);
+    const bool is_powered_on = system.IsPoweredOn();
+    for (const auto& func : apply_funcs) {
+        func(is_powered_on);
+    }
 }
 
 void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) {
@@ -113,71 +77,6 @@ void ConfigureGraphicsAdvanced::RetranslateUI() {
     ui->retranslateUi(this);
 }
 
-void ConfigureGraphicsAdvanced::SetupPerGameUI() {
-    // Disable if not global (only happens during game)
-    if (Settings::IsConfiguringGlobal()) {
-        ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal());
-        ui->async_present->setEnabled(Settings::values.async_presentation.UsingGlobal());
-        ui->renderer_force_max_clock->setEnabled(
-            Settings::values.renderer_force_max_clock.UsingGlobal());
-        ui->use_reactive_flushing->setEnabled(Settings::values.use_reactive_flushing.UsingGlobal());
-        ui->async_astc->setEnabled(Settings::values.async_astc.UsingGlobal());
-        ui->astc_recompression_combobox->setEnabled(
-            Settings::values.astc_recompression.UsingGlobal());
-        ui->use_asynchronous_shaders->setEnabled(
-            Settings::values.use_asynchronous_shaders.UsingGlobal());
-        ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal());
-        ui->use_vulkan_driver_pipeline_cache->setEnabled(
-            Settings::values.use_vulkan_driver_pipeline_cache.UsingGlobal());
-        ui->anisotropic_filtering_combobox->setEnabled(
-            Settings::values.max_anisotropy.UsingGlobal());
-        ui->enable_compute_pipelines_checkbox->setEnabled(
-            Settings::values.enable_compute_pipelines.UsingGlobal());
-        ui->use_video_framerate_checkbox->setEnabled(
-            Settings::values.use_video_framerate.UsingGlobal());
-        ui->barrier_feedback_loops_checkbox->setEnabled(
-            Settings::values.barrier_feedback_loops.UsingGlobal());
-
-        return;
-    }
-
-    ConfigurationShared::SetColoredTristate(ui->async_present, Settings::values.async_presentation,
-                                            async_present);
-    ConfigurationShared::SetColoredTristate(ui->renderer_force_max_clock,
-                                            Settings::values.renderer_force_max_clock,
-                                            renderer_force_max_clock);
-    ConfigurationShared::SetColoredTristate(
-        ui->use_reactive_flushing, Settings::values.use_reactive_flushing, use_reactive_flushing);
-    ConfigurationShared::SetColoredTristate(ui->async_astc, Settings::values.async_astc,
-                                            async_astc);
-    ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders,
-                                            Settings::values.use_asynchronous_shaders,
-                                            use_asynchronous_shaders);
-    ConfigurationShared::SetColoredTristate(ui->use_fast_gpu_time,
-                                            Settings::values.use_fast_gpu_time, use_fast_gpu_time);
-    ConfigurationShared::SetColoredTristate(ui->use_vulkan_driver_pipeline_cache,
-                                            Settings::values.use_vulkan_driver_pipeline_cache,
-                                            use_vulkan_driver_pipeline_cache);
-    ConfigurationShared::SetColoredTristate(ui->enable_compute_pipelines_checkbox,
-                                            Settings::values.enable_compute_pipelines,
-                                            enable_compute_pipelines);
-    ConfigurationShared::SetColoredTristate(ui->use_video_framerate_checkbox,
-                                            Settings::values.use_video_framerate,
-                                            use_video_framerate);
-    ConfigurationShared::SetColoredTristate(ui->barrier_feedback_loops_checkbox,
-                                            Settings::values.barrier_feedback_loops,
-                                            barrier_feedback_loops);
-    ConfigurationShared::SetColoredComboBox(
-        ui->gpu_accuracy, ui->label_gpu_accuracy,
-        static_cast<int>(Settings::values.gpu_accuracy.GetValue(true)));
-    ConfigurationShared::SetColoredComboBox(
-        ui->anisotropic_filtering_combobox, ui->af_label,
-        static_cast<int>(Settings::values.max_anisotropy.GetValue(true)));
-    ConfigurationShared::SetColoredComboBox(
-        ui->astc_recompression_combobox, ui->label_astc_recompression,
-        static_cast<int>(Settings::values.astc_recompression.GetValue(true)));
-}
-
 void ConfigureGraphicsAdvanced::ExposeComputeOption() {
-    ui->enable_compute_pipelines_checkbox->setVisible(true);
+    checkbox_enable_compute_pipelines->setVisible(true);
 }
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index 369a7c83e2..78b5389c32 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -4,51 +4,44 @@
 #pragma once
 
 #include <memory>
+#include <vector>
 #include <QWidget>
+#include "yuzu/configuration/configuration_shared.h"
 
 namespace Core {
 class System;
 }
 
-namespace ConfigurationShared {
-enum class CheckState;
-}
-
 namespace Ui {
 class ConfigureGraphicsAdvanced;
 }
 
-class ConfigureGraphicsAdvanced : public QWidget {
-    Q_OBJECT
+namespace ConfigurationShared {
+class Builder;
+}
 
+class ConfigureGraphicsAdvanced : public ConfigurationShared::Tab {
 public:
-    explicit ConfigureGraphicsAdvanced(const Core::System& system_, QWidget* parent = nullptr);
+    explicit ConfigureGraphicsAdvanced(
+        const Core::System& system_, std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
+        const ConfigurationShared::Builder& builder, QWidget* parent = nullptr);
     ~ConfigureGraphicsAdvanced() override;
 
-    void ApplyConfiguration();
-    void SetConfiguration();
+    void ApplyConfiguration() override;
+    void SetConfiguration() override;
 
     void ExposeComputeOption();
 
 private:
+    void Setup(const ConfigurationShared::Builder& builder);
     void changeEvent(QEvent* event) override;
     void RetranslateUI();
 
-    void SetupPerGameUI();
-
     std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui;
 
-    ConfigurationShared::CheckState async_present;
-    ConfigurationShared::CheckState renderer_force_max_clock;
-    ConfigurationShared::CheckState use_vsync;
-    ConfigurationShared::CheckState async_astc;
-    ConfigurationShared::CheckState use_reactive_flushing;
-    ConfigurationShared::CheckState use_asynchronous_shaders;
-    ConfigurationShared::CheckState use_fast_gpu_time;
-    ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache;
-    ConfigurationShared::CheckState enable_compute_pipelines;
-    ConfigurationShared::CheckState use_video_framerate;
-    ConfigurationShared::CheckState barrier_feedback_loops;
-
     const Core::System& system;
+
+    std::vector<std::function<void(bool)>> apply_funcs;
+
+    QWidget* checkbox_enable_compute_pipelines{};
 };
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index d527a6f38b..37a854ca3f 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -26,8 +26,8 @@
        </property>
        <layout class="QVBoxLayout" name="verticalLayout_3">
         <item>
-         <widget class="QWidget" name="gpu_accuracy_layout" native="true">
-          <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <widget class="QWidget" name="populate_target" native="true">
+          <layout class="QVBoxLayout" name="verticalLayout">
            <property name="leftMargin">
             <number>0</number>
            </property>
@@ -40,233 +40,6 @@
            <property name="bottomMargin">
             <number>0</number>
            </property>
-           <item>
-            <widget class="QLabel" name="label_gpu_accuracy">
-             <property name="text">
-              <string>Accuracy Level:</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QComboBox" name="gpu_accuracy">
-             <item>
-              <property name="text">
-               <string notr="true">Normal</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string notr="true">High</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string notr="true">Extreme(very slow)</string>
-              </property>
-             </item>
-            </widget>
-           </item>
-          </layout>
-         </widget>
-        </item>
-        <item>
-         <widget class="QWidget" name="astc_recompression_layout" native="true">
-          <layout class="QHBoxLayout" name="horizontalLayout_3">
-            <property name="leftMargin">
-              <number>0</number>
-            </property>
-            <property name="topMargin">
-              <number>0</number>
-            </property>
-            <property name="rightMargin">
-              <number>0</number>
-            </property>
-            <property name="bottomMargin">
-              <number>0</number>
-            </property>
-            <item>
-              <widget class="QLabel" name="label_astc_recompression">
-              <property name="text">
-                <string>ASTC recompression:</string>
-              </property>
-              </widget>
-            </item>
-            <item>
-              <widget class="QComboBox" name="astc_recompression_combobox">
-                <item>
-                <property name="text">
-                  <string>Uncompressed (Best quality)</string>
-                </property>
-                </item>
-                <item>
-                <property name="text">
-                  <string>BC1 (Low quality)</string>
-                </property>
-                </item>
-                <item>
-                <property name="text">
-                  <string>BC3 (Medium quality)</string>
-                </property>
-                </item>
-              </widget>
-            </item>
-          </layout>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="async_present">
-          <property name="text">
-           <string>Enable asynchronous presentation (Vulkan only)</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="renderer_force_max_clock">
-          <property name="toolTip">
-           <string>Runs work in the background while waiting for graphics commands to keep the GPU from lowering its clock speed.</string>
-          </property>
-          <property name="text">
-           <string>Force maximum clocks (Vulkan only)</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="async_astc">
-          <property name="toolTip">
-           <string>Enables asynchronous ASTC texture decoding, which may reduce load time stutter. This feature is experimental.</string>
-          </property>
-          <property name="text">
-           <string>Decode ASTC textures asynchronously (Hack)</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="use_reactive_flushing">
-          <property name="toolTip">
-           <string>Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory.</string>
-          </property>
-          <property name="text">
-           <string>Enable Reactive Flushing</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="use_asynchronous_shaders">
-          <property name="toolTip">
-           <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string>
-          </property>
-          <property name="text">
-           <string>Use asynchronous shader building (Hack)</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="use_fast_gpu_time">
-          <property name="toolTip">
-           <string>Enables Fast GPU Time. This option will force most games to run at their highest native resolution.</string>
-          </property>
-          <property name="text">
-           <string>Use Fast GPU Time (Hack)</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="use_vulkan_driver_pipeline_cache">
-          <property name="toolTip">
-           <string>Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files internally.</string>
-          </property>
-          <property name="text">
-           <string>Use Vulkan pipeline cache</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="enable_compute_pipelines_checkbox">
-          <property name="toolTip">
-           <string>Enable compute pipelines, required by some games. This setting only exists for Intel proprietary drivers, and may crash if enabled.
-Compute pipelines are always enabled on all other drivers.</string>
-          </property>
-          <property name="text">
-           <string>Enable Compute Pipelines (Intel Vulkan only)</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="use_video_framerate_checkbox">
-          <property name="toolTip">
-           <string>Run the game at normal speed during video playback, even when the framerate is unlocked.</string>
-          </property>
-          <property name="text">
-           <string>Sync to framerate of video playback</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="barrier_feedback_loops_checkbox">
-          <property name="toolTip">
-           <string>Improves rendering of transparency effects in specific games.</string>
-          </property>
-          <property name="text">
-           <string>Barrier feedback loops</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QWidget" name="af_layout" native="true">
-          <layout class="QHBoxLayout" name="horizontalLayout_1">
-           <property name="leftMargin">
-            <number>0</number>
-           </property>
-           <property name="topMargin">
-            <number>0</number>
-           </property>
-           <property name="rightMargin">
-            <number>0</number>
-           </property>
-           <property name="bottomMargin">
-            <number>0</number>
-           </property>
-           <item>
-            <widget class="QLabel" name="af_label">
-             <property name="text">
-              <string>Anisotropic Filtering:</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QComboBox" name="anisotropic_filtering_combobox">
-             <item>
-              <property name="text">
-               <string>Automatic</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>Default</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>2x</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>4x</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>8x</string>
-              </property>
-             </item>
-             <item>
-              <property name="text">
-               <string>16x</string>
-              </property>
-             </item>
-            </widget>
-           </item>
           </layout>
          </widget>
         </item>
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index eb96e6068c..cd8b3012e8 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -17,6 +17,7 @@
 #include <QTimer>
 
 #include "common/fs/fs_util.h"
+#include "configuration/shared_widget.h"
 #include "core/core.h"
 #include "core/file_sys/control_metadata.h"
 #include "core/file_sys/patch_manager.h"
@@ -24,9 +25,9 @@
 #include "core/loader/loader.h"
 #include "ui_configure_per_game.h"
 #include "yuzu/configuration/config.h"
+#include "yuzu/configuration/configuration_shared.h"
 #include "yuzu/configuration/configure_audio.h"
 #include "yuzu/configuration/configure_cpu.h"
-#include "yuzu/configuration/configure_general.h"
 #include "yuzu/configuration/configure_graphics.h"
 #include "yuzu/configuration/configure_graphics_advanced.h"
 #include "yuzu/configuration/configure_input_per_game.h"
@@ -41,26 +42,28 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
                                    std::vector<VkDeviceInfo::Record>& vk_device_records,
                                    Core::System& system_)
     : QDialog(parent),
-      ui(std::make_unique<Ui::ConfigurePerGame>()), title_id{title_id_}, system{system_} {
+      ui(std::make_unique<Ui::ConfigurePerGame>()), title_id{title_id_}, system{system_},
+      builder{std::make_unique<ConfigurationShared::Builder>(this, !system_.IsPoweredOn())},
+      tab_group{std::make_shared<std::vector<ConfigurationShared::Tab*>>()} {
     const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name));
     const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename())
                                                 : fmt::format("{:016X}", title_id);
     game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig);
 
     addons_tab = std::make_unique<ConfigurePerGameAddons>(system_, this);
-    audio_tab = std::make_unique<ConfigureAudio>(system_, this);
-    cpu_tab = std::make_unique<ConfigureCpu>(system_, this);
-    general_tab = std::make_unique<ConfigureGeneral>(system_, this);
-    graphics_advanced_tab = std::make_unique<ConfigureGraphicsAdvanced>(system_, this);
+    audio_tab = std::make_unique<ConfigureAudio>(system_, tab_group, *builder, this);
+    cpu_tab = std::make_unique<ConfigureCpu>(system_, tab_group, *builder, this);
+    graphics_advanced_tab =
+        std::make_unique<ConfigureGraphicsAdvanced>(system_, tab_group, *builder, this);
     graphics_tab = std::make_unique<ConfigureGraphics>(
-        system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, this);
+        system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
+        tab_group, *builder, this);
     input_tab = std::make_unique<ConfigureInputPerGame>(system_, game_config.get(), this);
-    system_tab = std::make_unique<ConfigureSystem>(system_, this);
+    system_tab = std::make_unique<ConfigureSystem>(system_, tab_group, *builder, this);
 
     ui->setupUi(this);
 
     ui->tabWidget->addTab(addons_tab.get(), tr("Add-Ons"));
-    ui->tabWidget->addTab(general_tab.get(), tr("General"));
     ui->tabWidget->addTab(system_tab.get(), tr("System"));
     ui->tabWidget->addTab(cpu_tab.get(), tr("CPU"));
     ui->tabWidget->addTab(graphics_tab.get(), tr("Graphics"));
@@ -88,13 +91,10 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
 ConfigurePerGame::~ConfigurePerGame() = default;
 
 void ConfigurePerGame::ApplyConfiguration() {
+    for (const auto tab : *tab_group) {
+        tab->ApplyConfiguration();
+    }
     addons_tab->ApplyConfiguration();
-    general_tab->ApplyConfiguration();
-    cpu_tab->ApplyConfiguration();
-    system_tab->ApplyConfiguration();
-    graphics_tab->ApplyConfiguration();
-    graphics_advanced_tab->ApplyConfiguration();
-    audio_tab->ApplyConfiguration();
     input_tab->ApplyConfiguration();
 
     system.ApplySettings();
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h
index 7ec1ded062..1a727f32c0 100644
--- a/src/yuzu/configuration/configure_per_game.h
+++ b/src/yuzu/configuration/configure_per_game.h
@@ -10,9 +10,12 @@
 #include <QDialog>
 #include <QList>
 
+#include "configuration/shared_widget.h"
 #include "core/file_sys/vfs_types.h"
 #include "vk_device_info.h"
 #include "yuzu/configuration/config.h"
+#include "yuzu/configuration/configuration_shared.h"
+#include "yuzu/configuration/shared_translation.h"
 
 namespace Core {
 class System;
@@ -25,7 +28,6 @@ class InputSubsystem;
 class ConfigurePerGameAddons;
 class ConfigureAudio;
 class ConfigureCpu;
-class ConfigureGeneral;
 class ConfigureGraphics;
 class ConfigureGraphicsAdvanced;
 class ConfigureInputPerGame;
@@ -73,11 +75,12 @@ private:
     std::unique_ptr<Config> game_config;
 
     Core::System& system;
+    std::unique_ptr<ConfigurationShared::Builder> builder;
+    std::shared_ptr<std::vector<ConfigurationShared::Tab*>> tab_group;
 
     std::unique_ptr<ConfigurePerGameAddons> addons_tab;
     std::unique_ptr<ConfigureAudio> audio_tab;
     std::unique_ptr<ConfigureCpu> cpu_tab;
-    std::unique_ptr<ConfigureGeneral> general_tab;
     std::unique_ptr<ConfigureGraphicsAdvanced> graphics_advanced_tab;
     std::unique_ptr<ConfigureGraphics> graphics_tab;
     std::unique_ptr<ConfigureInputPerGame> input_tab;
diff --git a/src/yuzu/configuration/configure_per_game.ui b/src/yuzu/configuration/configure_per_game.ui
index 85c86e1070..99ba2fd180 100644
--- a/src/yuzu/configuration/configure_per_game.ui
+++ b/src/yuzu/configuration/configure_per_game.ui
@@ -2,6 +2,14 @@
 <ui version="4.0">
  <class>ConfigurePerGame</class>
  <widget class="QDialog" name="ConfigurePerGame">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>900</width>
+    <height>607</height>
+   </rect>
+  </property>
   <property name="minimumSize">
    <size>
     <width>900</width>
@@ -225,20 +233,31 @@
     </layout>
    </item>
    <item>
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QLabel" name="label_8">
+       <property name="text">
+        <string>Some settings are only available when a game is not running.</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QDialogButtonBox" name="buttonBox">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="standardButtons">
+        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
    </item>
   </layout>
  </widget>
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index f1ae312c65..c4833f4e70 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -3,16 +3,23 @@
 
 #include <chrono>
 #include <optional>
+#include <vector>
 
+#include <QCheckBox>
+#include <QComboBox>
+#include <QDateTimeEdit>
 #include <QFileDialog>
 #include <QGraphicsItem>
+#include <QLineEdit>
 #include <QMessageBox>
 #include "common/settings.h"
 #include "core/core.h"
 #include "core/hle/service/time/time_manager.h"
 #include "ui_configure_system.h"
+#include "yuzu/configuration/config.h"
 #include "yuzu/configuration/configuration_shared.h"
 #include "yuzu/configuration/configure_system.h"
+#include "yuzu/configuration/shared_widget.h"
 
 constexpr std::array<u32, 7> LOCALE_BLOCKLIST{
     // pzzefezrpnkzeidfej
@@ -37,44 +44,32 @@ static bool IsValidLocale(u32 region_index, u32 language_index) {
     return ((LOCALE_BLOCKLIST.at(region_index) >> language_index) & 1) == 0;
 }
 
-ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
-    : QWidget(parent), ui{std::make_unique<Ui::ConfigureSystem>()}, system{system_} {
+ConfigureSystem::ConfigureSystem(Core::System& system_,
+                                 std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group_,
+                                 const ConfigurationShared::Builder& builder, QWidget* parent)
+    : Tab(group_, parent), ui{std::make_unique<Ui::ConfigureSystem>()}, system{system_} {
     ui->setupUi(this);
 
-    connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
-        ui->rng_seed_edit->setEnabled(state == Qt::Checked);
-        if (state != Qt::Checked) {
-            ui->rng_seed_edit->setText(QStringLiteral("00000000"));
-        }
-    });
+    Setup(builder);
 
-    connect(ui->custom_rtc_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
-        ui->custom_rtc_edit->setEnabled(state == Qt::Checked);
-        if (state != Qt::Checked) {
-            ui->custom_rtc_edit->setDateTime(QDateTime::currentDateTime());
-        }
-    });
-
-    const auto locale_check = [this](int index) {
-        const auto region_index = ConfigurationShared::GetComboboxIndex(
-            Settings::values.region_index.GetValue(true), ui->combo_region);
-        const auto language_index = ConfigurationShared::GetComboboxIndex(
-            Settings::values.language_index.GetValue(true), ui->combo_language);
+    const auto locale_check = [this]() {
+        const auto region_index = combo_region->currentIndex();
+        const auto language_index = combo_language->currentIndex();
         const bool valid_locale = IsValidLocale(region_index, language_index);
         ui->label_warn_invalid_locale->setVisible(!valid_locale);
         if (!valid_locale) {
             ui->label_warn_invalid_locale->setText(
                 tr("Warning: \"%1\" is not a valid language for region \"%2\"")
-                    .arg(ui->combo_language->currentText())
-                    .arg(ui->combo_region->currentText()));
+                    .arg(combo_language->currentText())
+                    .arg(combo_region->currentText()));
         }
     };
 
-    connect(ui->combo_language, qOverload<int>(&QComboBox::currentIndexChanged), this,
-            locale_check);
-    connect(ui->combo_region, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check);
+    connect(combo_language, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check);
+    connect(combo_region, qOverload<int>(&QComboBox::currentIndexChanged), this, locale_check);
 
-    SetupPerGameUI();
+    ui->label_warn_invalid_locale->setVisible(false);
+    locale_check();
 
     SetConfiguration();
 }
@@ -93,137 +88,66 @@ void ConfigureSystem::RetranslateUI() {
     ui->retranslateUi(this);
 }
 
-void ConfigureSystem::SetConfiguration() {
-    enabled = !system.IsPoweredOn();
-    const auto rng_seed =
-        QStringLiteral("%1")
-            .arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'})
-            .toUpper();
-    const auto rtc_time = Settings::values.custom_rtc.value_or(QDateTime::currentSecsSinceEpoch());
+void ConfigureSystem::Setup(const ConfigurationShared::Builder& builder) {
+    auto& core_layout = *ui->core_widget->layout();
+    auto& system_layout = *ui->system_widget->layout();
 
-    ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value());
-    ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() &&
-                                  Settings::values.rng_seed.UsingGlobal());
-    ui->rng_seed_edit->setText(rng_seed);
+    std::map<u32, QWidget*> core_hold{};
+    std::map<u32, QWidget*> system_hold{};
 
-    ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value());
-    ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value());
-    ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time));
-    ui->device_name_edit->setText(
-        QString::fromUtf8(Settings::values.device_name.GetValue().c_str()));
-    ui->use_unsafe_extended_memory_layout->setEnabled(enabled);
-    ui->use_unsafe_extended_memory_layout->setChecked(
-        Settings::values.use_unsafe_extended_memory_layout.GetValue());
+    std::vector<Settings::BasicSetting*> settings;
+    auto push = [&settings](auto& list) {
+        for (auto setting : list) {
+            settings.push_back(setting);
+        }
+    };
 
-    if (Settings::IsConfiguringGlobal()) {
-        ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue());
-        ui->combo_region->setCurrentIndex(Settings::values.region_index.GetValue());
-        ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index.GetValue());
-    } else {
-        ConfigurationShared::SetPerGameSetting(ui->combo_language,
-                                               &Settings::values.language_index);
-        ConfigurationShared::SetPerGameSetting(ui->combo_region, &Settings::values.region_index);
-        ConfigurationShared::SetPerGameSetting(ui->combo_time_zone,
-                                               &Settings::values.time_zone_index);
+    push(Settings::values.linkage.by_category[Settings::Category::Core]);
+    push(Settings::values.linkage.by_category[Settings::Category::System]);
 
-        ConfigurationShared::SetHighlight(ui->label_language,
-                                          !Settings::values.language_index.UsingGlobal());
-        ConfigurationShared::SetHighlight(ui->label_region,
-                                          !Settings::values.region_index.UsingGlobal());
-        ConfigurationShared::SetHighlight(ui->label_timezone,
-                                          !Settings::values.time_zone_index.UsingGlobal());
+    for (auto setting : settings) {
+        ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs);
+
+        if (widget == nullptr) {
+            continue;
+        }
+        if (!widget->Valid()) {
+            widget->deleteLater();
+            continue;
+        }
+
+        if (setting->Id() == Settings::values.region_index.Id()) {
+            // Keep track of the region_index (and langauge_index) combobox to validate the selected
+            // settings
+            combo_region = widget->combobox;
+        } else if (setting->Id() == Settings::values.language_index.Id()) {
+            combo_language = widget->combobox;
+        }
+
+        switch (setting->GetCategory()) {
+        case Settings::Category::Core:
+            core_hold.emplace(setting->Id(), widget);
+            break;
+        case Settings::Category::System:
+            system_hold.emplace(setting->Id(), widget);
+            break;
+        default:
+            widget->deleteLater();
+        }
+    }
+    for (const auto& [label, widget] : core_hold) {
+        core_layout.addWidget(widget);
+    }
+    for (const auto& [id, widget] : system_hold) {
+        system_layout.addWidget(widget);
     }
 }
 
-void ConfigureSystem::ReadSystemSettings() {}
+void ConfigureSystem::SetConfiguration() {}
 
 void ConfigureSystem::ApplyConfiguration() {
-    // Allow setting custom RTC even if system is powered on,
-    // to allow in-game time to be fast forwarded
-    if (Settings::IsConfiguringGlobal()) {
-        if (ui->custom_rtc_checkbox->isChecked()) {
-            Settings::values.custom_rtc = ui->custom_rtc_edit->dateTime().toSecsSinceEpoch();
-            if (system.IsPoweredOn()) {
-                const s64 posix_time{*Settings::values.custom_rtc};
-                system.GetTimeManager().UpdateLocalSystemClockTime(posix_time);
-            }
-        } else {
-            Settings::values.custom_rtc = std::nullopt;
-        }
-    }
-
-    Settings::values.device_name = ui->device_name_edit->text().toStdString();
-
-    if (!enabled) {
-        return;
-    }
-
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index, ui->combo_language);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
-                                             ui->combo_time_zone);
-    ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_unsafe_extended_memory_layout,
-                                             ui->use_unsafe_extended_memory_layout,
-                                             use_unsafe_extended_memory_layout);
-
-    if (Settings::IsConfiguringGlobal()) {
-        // Guard if during game and set to game-specific value
-        if (Settings::values.rng_seed.UsingGlobal()) {
-            if (ui->rng_seed_checkbox->isChecked()) {
-                Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toUInt(nullptr, 16));
-            } else {
-                Settings::values.rng_seed.SetValue(std::nullopt);
-            }
-        }
-    } else {
-        switch (use_rng_seed) {
-        case ConfigurationShared::CheckState::On:
-        case ConfigurationShared::CheckState::Off:
-            Settings::values.rng_seed.SetGlobal(false);
-            if (ui->rng_seed_checkbox->isChecked()) {
-                Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toUInt(nullptr, 16));
-            } else {
-                Settings::values.rng_seed.SetValue(std::nullopt);
-            }
-            break;
-        case ConfigurationShared::CheckState::Global:
-            Settings::values.rng_seed.SetGlobal(false);
-            Settings::values.rng_seed.SetValue(std::nullopt);
-            Settings::values.rng_seed.SetGlobal(true);
-            break;
-        case ConfigurationShared::CheckState::Count:
-            break;
-        }
+    const bool powered_on = system.IsPoweredOn();
+    for (const auto& func : apply_funcs) {
+        func(powered_on);
     }
 }
-
-void ConfigureSystem::SetupPerGameUI() {
-    if (Settings::IsConfiguringGlobal()) {
-        ui->combo_language->setEnabled(Settings::values.language_index.UsingGlobal());
-        ui->combo_region->setEnabled(Settings::values.region_index.UsingGlobal());
-        ui->combo_time_zone->setEnabled(Settings::values.time_zone_index.UsingGlobal());
-        ui->rng_seed_checkbox->setEnabled(Settings::values.rng_seed.UsingGlobal());
-        ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.UsingGlobal());
-
-        return;
-    }
-
-    ConfigurationShared::SetColoredComboBox(ui->combo_language, ui->label_language,
-                                            Settings::values.language_index.GetValue(true));
-    ConfigurationShared::SetColoredComboBox(ui->combo_region, ui->label_region,
-                                            Settings::values.region_index.GetValue(true));
-    ConfigurationShared::SetColoredComboBox(ui->combo_time_zone, ui->label_timezone,
-                                            Settings::values.time_zone_index.GetValue(true));
-
-    ConfigurationShared::SetColoredTristate(
-        ui->rng_seed_checkbox, Settings::values.rng_seed.UsingGlobal(),
-        Settings::values.rng_seed.GetValue().has_value(),
-        Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed);
-
-    ConfigurationShared::SetColoredTristate(ui->use_unsafe_extended_memory_layout,
-                                            Settings::values.use_unsafe_extended_memory_layout,
-                                            use_unsafe_extended_memory_layout);
-
-    ui->custom_rtc_checkbox->setVisible(false);
-    ui->custom_rtc_edit->setVisible(false);
-}
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h
index ce1a91601c..eab99a48a7 100644
--- a/src/yuzu/configuration/configure_system.h
+++ b/src/yuzu/configuration/configure_system.h
@@ -3,45 +3,53 @@
 
 #pragma once
 
+#include <functional>
 #include <memory>
+#include <vector>
 
 #include <QWidget>
+#include "yuzu/configuration/configuration_shared.h"
 
+class QCheckBox;
+class QLineEdit;
+class QComboBox;
+class QDateTimeEdit;
 namespace Core {
 class System;
 }
 
-namespace ConfigurationShared {
-enum class CheckState;
-}
-
 namespace Ui {
 class ConfigureSystem;
 }
 
-class ConfigureSystem : public QWidget {
-    Q_OBJECT
+namespace ConfigurationShared {
+class Builder;
+}
 
+class ConfigureSystem : public ConfigurationShared::Tab {
 public:
-    explicit ConfigureSystem(Core::System& system_, QWidget* parent = nullptr);
+    explicit ConfigureSystem(Core::System& system_,
+                             std::shared_ptr<std::vector<ConfigurationShared::Tab*>> group,
+                             const ConfigurationShared::Builder& builder,
+                             QWidget* parent = nullptr);
     ~ConfigureSystem() override;
 
-    void ApplyConfiguration();
-    void SetConfiguration();
+    void ApplyConfiguration() override;
+    void SetConfiguration() override;
 
 private:
     void changeEvent(QEvent* event) override;
     void RetranslateUI();
 
-    void ReadSystemSettings();
+    void Setup(const ConfigurationShared::Builder& builder);
 
-    void SetupPerGameUI();
+    std::vector<std::function<void(bool)>> apply_funcs{};
 
     std::unique_ptr<Ui::ConfigureSystem> ui;
     bool enabled = false;
 
-    ConfigurationShared::CheckState use_rng_seed;
-    ConfigurationShared::CheckState use_unsafe_extended_memory_layout;
-
     Core::System& system;
+
+    QComboBox* combo_region;
+    QComboBox* combo_language;
 };
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui
index e0caecd5e3..2a735836e1 100644
--- a/src/yuzu/configuration/configure_system.ui
+++ b/src/yuzu/configuration/configure_system.ui
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>366</width>
+    <width>605</width>
     <height>483</height>
    </rect>
   </property>
@@ -22,470 +22,63 @@
      <item>
       <widget class="QGroupBox" name="group_system_settings">
        <property name="title">
-        <string>System Settings</string>
+        <string>System</string>
        </property>
        <layout class="QVBoxLayout" name="verticalLayout_2">
         <item>
-         <layout class="QGridLayout" name="gridLayout_2">
-          <item row="1" column="0">
-           <widget class="QLabel" name="label_region">
-            <property name="text">
-             <string>Region:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="2" column="1">
-           <widget class="QComboBox" name="combo_time_zone">
-            <item>
-             <property name="text">
-              <string>Auto</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Default</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>CET</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>CST6CDT</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Cuba</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>EET</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Egypt</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Eire</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>EST</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>EST5EDT</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>GB</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>GB-Eire</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>GMT</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>GMT+0</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>GMT-0</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>GMT0</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Greenwich</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Hongkong</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>HST</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Iceland</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Iran</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Israel</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Jamaica</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Japan</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Kwajalein</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Libya</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>MET</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>MST</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>MST7MDT</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Navajo</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>NZ</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>NZ-CHAT</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Poland</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Portugal</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>PRC</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>PST8PDT</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>ROC</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>ROK</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Singapore</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Turkey</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>UCT</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Universal</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>UTC</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>W-SU</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>WET</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Zulu</string>
-             </property>
-            </item>
-           </widget>
-          </item>
-          <item row="1" column="1">
-           <widget class="QComboBox" name="combo_region">
-            <item>
-             <property name="text">
-              <string>Japan</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>USA</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Europe</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Australia</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>China</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Korea</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Taiwan</string>
-             </property>
-            </item>
-           </widget>
-          </item>
-          <item row="2" column="0">
-           <widget class="QLabel" name="label_timezone">
-            <property name="text">
-             <string>Time Zone:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="0" column="1">
-           <widget class="QComboBox" name="combo_language">
-            <property name="toolTip">
-             <string>Note: this can be overridden when region setting is auto-select</string>
-            </property>
-            <item>
-             <property name="text">
-              <string>Japanese (日本語)</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>American English</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>French (français)</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>German (Deutsch)</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Italian (italiano)</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Spanish (español)</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Chinese</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Korean (한국어)</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Dutch (Nederlands)</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Portuguese (português)</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Russian (Русский)</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Taiwanese</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>British English</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Canadian French</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Latin American Spanish</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Simplified Chinese</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Traditional Chinese (正體中文)</string>
-             </property>
-            </item>
-            <item>
-             <property name="text">
-              <string>Brazilian Portuguese (português do Brasil)</string>
-             </property>
-            </item>
-           </widget>
-          </item>
-          <item row="4" column="0">
-           <widget class="QCheckBox" name="custom_rtc_checkbox">
-            <property name="text">
-             <string>Custom RTC</string>
-            </property>
-           </widget>
-          </item>
-          <item row="0" column="0">
-           <widget class="QLabel" name="label_language">
-            <property name="text">
-             <string>Language</string>
-            </property>
-           </widget>
-          </item>
-          <item row="5" column="0">
-           <widget class="QCheckBox" name="rng_seed_checkbox">
-            <property name="text">
-             <string>RNG Seed</string>
-            </property>
-           </widget>
-          </item>
-          <item row="6" column="0">
-           <widget class="QLabel" name="device_name_label">
-            <property name="text">
-             <string>Device Name</string>
-            </property>
-           </widget>
-          </item>
-          <item row="4" column="1">
-           <widget class="QDateTimeEdit" name="custom_rtc_edit">
-            <property name="minimumDate">
-             <date>
-              <year>1970</year>
-              <month>1</month>
-              <day>1</day>
-             </date>
-            </property>
-           </widget>
-          </item>
-          <item row="6" column="1">
-           <widget class="QLineEdit" name="device_name_edit">
-            <property name="maxLength">
-             <number>128</number>
-            </property>
-           </widget>
-          </item>
-          <item row="5" column="1">
-           <widget class="QLineEdit" name="rng_seed_edit">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="font">
-             <font>
-              <family>Lucida Console</family>
-             </font>
-            </property>
-            <property name="inputMask">
-             <string notr="true">HHHHHHHH</string>
-            </property>
-            <property name="maxLength">
-             <number>8</number>
-            </property>
-           </widget>
-          </item>
-          <item row="7" column="0">
-           <widget class="QCheckBox" name="use_unsafe_extended_memory_layout">
-            <property name="text">
-             <string>Unsafe extended memory layout (8GB DRAM)</string>
-            </property>
-           </widget>
-          </item>
-         </layout>
+         <widget class="QWidget" name="system_widget" native="true">
+          <layout class="QVBoxLayout" name="verticalLayout_3">
+           <property name="leftMargin">
+            <number>0</number>
+           </property>
+           <property name="topMargin">
+            <number>0</number>
+           </property>
+           <property name="rightMargin">
+            <number>0</number>
+           </property>
+           <property name="bottomMargin">
+            <number>0</number>
+           </property>
+          </layout>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_warn_invalid_locale">
+          <property name="text">
+           <string/>
+          </property>
+          <property name="wordWrap">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <widget class="QGroupBox" name="groupBox">
+       <property name="title">
+        <string>Core</string>
+       </property>
+       <layout class="QVBoxLayout" name="verticalLayout_6">
+        <item>
+         <widget class="QWidget" name="core_widget" native="true">
+          <layout class="QVBoxLayout" name="verticalLayout_5">
+           <property name="leftMargin">
+            <number>0</number>
+           </property>
+           <property name="topMargin">
+            <number>0</number>
+           </property>
+           <property name="rightMargin">
+            <number>0</number>
+           </property>
+           <property name="bottomMargin">
+            <number>0</number>
+           </property>
+          </layout>
+         </widget>
         </item>
        </layout>
       </widget>
@@ -503,26 +96,6 @@
        </property>
       </spacer>
      </item>
-     <item>
-      <widget class="QLabel" name="label_warn_invalid_locale">
-       <property name="text">
-        <string></string>
-       </property>
-       <property name="wordWrap">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QLabel" name="label_disable_info">
-       <property name="text">
-        <string>System settings are available only when game is not running.</string>
-       </property>
-       <property name="wordWrap">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
     </layout>
    </item>
   </layout>
diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp
new file mode 100644
index 0000000000..335810788a
--- /dev/null
+++ b/src/yuzu/configuration/shared_translation.cpp
@@ -0,0 +1,388 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/time_zone.h"
+#include "yuzu/configuration/shared_translation.h"
+
+#include <map>
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <QWidget>
+#include "common/settings.h"
+#include "common/settings_enums.h"
+#include "common/settings_setting.h"
+#include "yuzu/uisettings.h"
+
+namespace ConfigurationShared {
+
+std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
+    std::unique_ptr<TranslationMap> translations = std::make_unique<TranslationMap>();
+    const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); };
+
+#define INSERT(SETTINGS, ID, NAME, TOOLTIP)                                                        \
+    translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{tr((NAME)), tr((TOOLTIP))}})
+
+    // A setting can be ignored by giving it a blank name
+
+    // Audio
+    INSERT(Settings, sink_id, "Output Engine:", "");
+    INSERT(Settings, audio_output_device_id, "Output Device:", "");
+    INSERT(Settings, audio_input_device_id, "Input Device:", "");
+    INSERT(Settings, audio_muted, "Mute audio when in background", "");
+    INSERT(Settings, volume, "Volume:", "");
+    INSERT(Settings, dump_audio_commands, "", "");
+
+    // Core
+    INSERT(Settings, use_multi_core, "Multicore CPU Emulation", "");
+    INSERT(Settings, memory_layout_mode, "Memory Layout", "");
+    INSERT(Settings, use_speed_limit, "", "");
+    INSERT(Settings, speed_limit, "Limit Speed Percent", "");
+
+    // Cpu
+    INSERT(Settings, cpu_accuracy, "Accuracy:", "");
+
+    // Cpu Debug
+
+    // Cpu Unsafe
+    INSERT(Settings, cpuopt_unsafe_unfuse_fma,
+           "Unfuse FMA (improve performance on CPUs without FMA)",
+           "This option improves speed by reducing accuracy of fused-multiply-add instructions on "
+           "CPUs without native FMA support.");
+    INSERT(Settings, cpuopt_unsafe_reduce_fp_error, "Faster FRSQRTE and FRECPE",
+           "This option improves the speed of some approximate floating-point functions by using "
+           "less accurate native approximations.");
+    INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr, "Faster ASIMD instructions (32 bits only)",
+           "This option improves the speed of 32 bits ASIMD floating-point functions by running "
+           "with incorrect rounding modes.");
+    INSERT(Settings, cpuopt_unsafe_inaccurate_nan, "Inaccurate NaN handling",
+           "This option improves speed by removing NaN checking. Please note this also reduces "
+           "accuracy of certain floating-point instructions.");
+    INSERT(
+        Settings, cpuopt_unsafe_fastmem_check, "Disable address space checks",
+        "This option improves speed by eliminating a safety check before every memory read/write "
+        "in guest. Disabling it may allow a game to read/write the emulator's memory.");
+    INSERT(Settings, cpuopt_unsafe_ignore_global_monitor, "Ignore global monitor",
+           "This option improves speed by relying only on the semantics of cmpxchg to ensure "
+           "safety of exclusive access instructions. Please note this may result in deadlocks and "
+           "other race conditions.");
+
+    // Renderer
+    INSERT(Settings, renderer_backend, "API:", "");
+    INSERT(Settings, vulkan_device, "Device:", "");
+    INSERT(Settings, shader_backend, "Shader Backend:", "");
+    INSERT(Settings, resolution_setup, "Resolution:", "");
+    INSERT(Settings, scaling_filter, "Window Adapting Filter:", "");
+    INSERT(Settings, fsr_sharpening_slider, "FSR Sharpness:", "");
+    INSERT(Settings, anti_aliasing, "Anti-Aliasing Method:", "");
+    INSERT(Settings, fullscreen_mode, "Fullscreen Mode:", "");
+    INSERT(Settings, aspect_ratio, "Aspect Ratio:", "");
+    INSERT(Settings, use_disk_shader_cache, "Use disk pipeline cache", "");
+    INSERT(Settings, use_asynchronous_gpu_emulation, "Use asynchronous GPU emulation", "");
+    INSERT(Settings, nvdec_emulation, "NVDEC emulation:", "");
+    INSERT(Settings, accelerate_astc, "ASTC Decoding Method:", "");
+    INSERT(Settings, astc_recompression, "ASTC Recompression Method:", "");
+    INSERT(Settings, vsync_mode, "VSync Mode:",
+           "FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
+           "refresh rate.\nFIFO Relaxed is similar to FIFO but allows tearing as it recovers from "
+           "a slow down.\nMailbox can have lower latency than FIFO and does not tear but may drop "
+           "frames.\nImmediate (no synchronization) just presents whatever is available and can "
+           "exhibit tearing.");
+    INSERT(Settings, bg_red, "", "");
+    INSERT(Settings, bg_green, "", "");
+    INSERT(Settings, bg_blue, "", "");
+
+    // Renderer (Advanced Graphics)
+    INSERT(Settings, async_presentation, "Enable asynchronous presentation (Vulkan only)", "");
+    INSERT(Settings, renderer_force_max_clock, "Force maximum clocks (Vulkan only)",
+           "Runs work in the background while waiting for graphics commands to keep the GPU from "
+           "lowering its clock speed.");
+    INSERT(Settings, max_anisotropy, "Anisotropic Filtering:", "");
+    INSERT(Settings, gpu_accuracy, "Accuracy Level:", "");
+    INSERT(Settings, use_asynchronous_shaders, "Use asynchronous shader building (Hack)",
+           "Enables asynchronous shader compilation, which may reduce shader stutter. This feature "
+           "is experimental.");
+    INSERT(Settings, use_fast_gpu_time, "Use Fast GPU Time (Hack)",
+           "Enables Fast GPU Time. This option will force most games to run at their highest "
+           "native resolution.");
+    INSERT(Settings, use_vulkan_driver_pipeline_cache, "Use Vulkan pipeline cache",
+           "Enables GPU vendor-specific pipeline cache. This option can improve shader loading "
+           "time significantly in cases where the Vulkan driver does not store pipeline cache "
+           "files internally.");
+    INSERT(Settings, enable_compute_pipelines, "Enable Compute Pipelines (Intel Vulkan Only)",
+           "Enable compute pipelines, required by some games.\nThis setting only exists for Intel "
+           "proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled "
+           "on all other drivers.");
+    INSERT(Settings, use_reactive_flushing, "Enable Reactive Flushing",
+           "Uses reactive flushing instead of predictive flushing, allowing more accurate memory "
+           "syncing.");
+    INSERT(Settings, use_video_framerate, "Sync to framerate of video playback",
+           "Run the game at normal speed during video playback, even when the framerate is "
+           "unlocked.");
+    INSERT(Settings, barrier_feedback_loops, "Barrier feedback loops",
+           "Improves rendering of transparency effects in specific games.");
+
+    // Renderer (Debug)
+
+    // System
+    INSERT(Settings, rng_seed, "RNG Seed", "");
+    INSERT(Settings, rng_seed_enabled, "", "");
+    INSERT(Settings, device_name, "Device Name", "");
+    INSERT(Settings, custom_rtc, "Custom RTC", "");
+    INSERT(Settings, custom_rtc_enabled, "", "");
+    INSERT(Settings, language_index,
+           "Language:", "Note: this can be overridden when region setting is auto-select");
+    INSERT(Settings, region_index, "Region:", "");
+    INSERT(Settings, time_zone_index, "Time Zone:", "");
+    INSERT(Settings, sound_index, "Sound Output Mode:", "");
+    INSERT(Settings, use_docked_mode, "", "");
+    INSERT(Settings, current_user, "", "");
+
+    // Controls
+
+    // Data Storage
+
+    // Debugging
+
+    // Debugging Graphics
+
+    // Network
+
+    // Web Service
+
+    // Ui
+
+    // Ui General
+    INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", "");
+    INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", "");
+    INSERT(UISettings, confirm_before_closing, "Confirm exit while emulation is running", "");
+    INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", "");
+    INSERT(UISettings, controller_applet_disabled, "Disable controller applet", "");
+
+    // Ui Debugging
+
+    // Ui Multiplayer
+
+    // Ui Games list
+
+#undef INSERT
+
+    return translations;
+}
+
+std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
+    std::unique_ptr<ComboboxTranslationMap> translations =
+        std::make_unique<ComboboxTranslationMap>();
+    const auto& tr = [&](const char* text, const char* context = "") {
+        return parent->tr(text, context);
+    };
+
+#define PAIR(ENUM, VALUE, TRANSLATION)                                                             \
+    { static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION) }
+#define CTX_PAIR(ENUM, VALUE, TRANSLATION, CONTEXT)                                                \
+    { static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION, CONTEXT) }
+
+    // Intentionally skipping VSyncMode to let the UI fill that one out
+
+    translations->insert({Settings::EnumMetadata<Settings::AstcDecodeMode>::Index(),
+                          {
+                              PAIR(AstcDecodeMode, Cpu, "CPU"),
+                              PAIR(AstcDecodeMode, Gpu, "GPU"),
+                              PAIR(AstcDecodeMode, CpuAsynchronous, "CPU Asynchronous"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::AstcRecompression>::Index(),
+                          {
+                              PAIR(AstcRecompression, Uncompressed, "Uncompressed (Best quality)"),
+                              PAIR(AstcRecompression, Bc1, "BC1 (Low quality)"),
+                              PAIR(AstcRecompression, Bc3, "BC3 (Medium quality)"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(),
+                          {
+#ifdef HAS_OPENGL
+                              PAIR(RendererBackend, OpenGL, "OpenGL"),
+#endif
+                              PAIR(RendererBackend, Vulkan, "Vulkan"),
+                              PAIR(RendererBackend, Null, "Null"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::ShaderBackend>::Index(),
+                          {
+                              PAIR(ShaderBackend, Glsl, "GLSL"),
+                              PAIR(ShaderBackend, Glasm, "GLASM (Assembly Shaders, NVIDIA Only)"),
+                              PAIR(ShaderBackend, SpirV, "SPIR-V (Experimental, Mesa Only)"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(),
+                          {
+                              PAIR(GpuAccuracy, Normal, "Normal"),
+                              PAIR(GpuAccuracy, High, "High"),
+                              PAIR(GpuAccuracy, Extreme, "Extreme"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
+                          {
+                              PAIR(CpuAccuracy, Auto, "Auto"),
+                              PAIR(CpuAccuracy, Accurate, "Accurate"),
+                              PAIR(CpuAccuracy, Unsafe, "Unsafe"),
+                              PAIR(CpuAccuracy, Paranoid, "Paranoid (disables most optimizations)"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::FullscreenMode>::Index(),
+                          {
+                              PAIR(FullscreenMode, Borderless, "Borderless Windowed"),
+                              PAIR(FullscreenMode, Exclusive, "Exclusive Fullscreen"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::NvdecEmulation>::Index(),
+                          {
+                              PAIR(NvdecEmulation, Off, "No Video Output"),
+                              PAIR(NvdecEmulation, Cpu, "CPU Video Decoding"),
+                              PAIR(NvdecEmulation, Gpu, "GPU Video Decoding (Default)"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::ResolutionSetup>::Index(),
+                          {
+                              PAIR(ResolutionSetup, Res1_2X, "0.5X (360p/540p) [EXPERIMENTAL]"),
+                              PAIR(ResolutionSetup, Res3_4X, "0.75X (540p/810p) [EXPERIMENTAL]"),
+                              PAIR(ResolutionSetup, Res1X, "1X (720p/1080p)"),
+                              PAIR(ResolutionSetup, Res3_2X, "1.5X (1080p/1620p) [EXPERIMENTAL]"),
+                              PAIR(ResolutionSetup, Res2X, "2X (1440p/2160p)"),
+                              PAIR(ResolutionSetup, Res3X, "3X (2160p/3240p)"),
+                              PAIR(ResolutionSetup, Res4X, "4X (2880p/4320p)"),
+                              PAIR(ResolutionSetup, Res5X, "5X (3600p/5400p)"),
+                              PAIR(ResolutionSetup, Res6X, "6X (4320p/6480p)"),
+                              PAIR(ResolutionSetup, Res7X, "7X (5040p/7560p)"),
+                              PAIR(ResolutionSetup, Res8X, "8X (5760p/8640p)"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::ScalingFilter>::Index(),
+                          {
+                              PAIR(ScalingFilter, NearestNeighbor, "Nearest Neighbor"),
+                              PAIR(ScalingFilter, Bilinear, "Bilinear"),
+                              PAIR(ScalingFilter, Bicubic, "Bicubic"),
+                              PAIR(ScalingFilter, Gaussian, "Gaussian"),
+                              PAIR(ScalingFilter, ScaleForce, "ScaleForce"),
+                              PAIR(ScalingFilter, Fsr, "AMD FidelityFX™️ Super Resolution"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::AntiAliasing>::Index(),
+                          {
+                              PAIR(AntiAliasing, None, "None"),
+                              PAIR(AntiAliasing, Fxaa, "FXAA"),
+                              PAIR(AntiAliasing, Smaa, "SMAA"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::AspectRatio>::Index(),
+                          {
+                              PAIR(AspectRatio, R16_9, "Default (16:9)"),
+                              PAIR(AspectRatio, R4_3, "Force 4:3"),
+                              PAIR(AspectRatio, R21_9, "Force 21:9"),
+                              PAIR(AspectRatio, R16_10, "Force 16:10"),
+                              PAIR(AspectRatio, Stretch, "Stretch to Window"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::AnisotropyMode>::Index(),
+                          {
+                              PAIR(AnisotropyMode, Automatic, "Automatic"),
+                              PAIR(AnisotropyMode, Default, "Default"),
+                              PAIR(AnisotropyMode, X2, "2x"),
+                              PAIR(AnisotropyMode, X4, "4x"),
+                              PAIR(AnisotropyMode, X8, "8x"),
+                              PAIR(AnisotropyMode, X16, "16x"),
+                          }});
+    translations->insert(
+        {Settings::EnumMetadata<Settings::Language>::Index(),
+         {
+             PAIR(Language, Japanese, "Japanese (日本語)"),
+             PAIR(Language, EnglishAmerican, "American English"),
+             PAIR(Language, French, "French (français)"),
+             PAIR(Language, German, "German (Deutsch)"),
+             PAIR(Language, Italian, "Italian (italiano)"),
+             PAIR(Language, Spanish, "Spanish (español)"),
+             PAIR(Language, Chinese, "Chinese"),
+             PAIR(Language, Korean, "Korean (한국어)"),
+             PAIR(Language, Dutch, "Dutch (Nederlands)"),
+             PAIR(Language, Portuguese, "Portuguese (português)"),
+             PAIR(Language, Russian, "Russian (Русский)"),
+             PAIR(Language, Taiwanese, "Taiwanese"),
+             PAIR(Language, EnglishBritish, "British English"),
+             PAIR(Language, FrenchCanadian, "Canadian French"),
+             PAIR(Language, SpanishLatin, "Latin American Spanish"),
+             PAIR(Language, ChineseSimplified, "Simplified Chinese"),
+             PAIR(Language, ChineseTraditional, "Traditional Chinese (正體中文)"),
+             PAIR(Language, PortugueseBrazilian, "Brazilian Portuguese (português do Brasil)"),
+         }});
+    translations->insert({Settings::EnumMetadata<Settings::Region>::Index(),
+                          {
+                              PAIR(Region, Japan, "Japan"),
+                              PAIR(Region, Usa, "USA"),
+                              PAIR(Region, Europe, "Europe"),
+                              PAIR(Region, Australia, "Australia"),
+                              PAIR(Region, China, "China"),
+                              PAIR(Region, Korea, "Korea"),
+                              PAIR(Region, Taiwan, "Taiwan"),
+                          }});
+    translations->insert(
+        {Settings::EnumMetadata<Settings::TimeZone>::Index(),
+         {
+             {static_cast<u32>(Settings::TimeZone::Auto),
+              tr("Auto (%1)", "Auto select time zone")
+                  .arg(QString::fromStdString(
+                      Settings::GetTimeZoneString(Settings::TimeZone::Auto)))},
+             {static_cast<u32>(Settings::TimeZone::Default),
+              tr("Default (%1)", "Default time zone")
+                  .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))},
+             PAIR(TimeZone, Cet, "CET"),
+             PAIR(TimeZone, Cst6Cdt, "CST6CDT"),
+             PAIR(TimeZone, Cuba, "Cuba"),
+             PAIR(TimeZone, Eet, "EET"),
+             PAIR(TimeZone, Egypt, "Egypt"),
+             PAIR(TimeZone, Eire, "Eire"),
+             PAIR(TimeZone, Est, "EST"),
+             PAIR(TimeZone, Est5Edt, "EST5EDT"),
+             PAIR(TimeZone, Gb, "GB"),
+             PAIR(TimeZone, GbEire, "GB-Eire"),
+             PAIR(TimeZone, Gmt, "GMT"),
+             PAIR(TimeZone, GmtPlusZero, "GMT+0"),
+             PAIR(TimeZone, GmtMinusZero, "GMT-0"),
+             PAIR(TimeZone, GmtZero, "GMT0"),
+             PAIR(TimeZone, Greenwich, "Greenwich"),
+             PAIR(TimeZone, Hongkong, "Hongkong"),
+             PAIR(TimeZone, Hst, "HST"),
+             PAIR(TimeZone, Iceland, "Iceland"),
+             PAIR(TimeZone, Iran, "Iran"),
+             PAIR(TimeZone, Israel, "Israel"),
+             PAIR(TimeZone, Jamaica, "Jamaica"),
+             PAIR(TimeZone, Japan, "Japan"),
+             PAIR(TimeZone, Kwajalein, "Kwajalein"),
+             PAIR(TimeZone, Libya, "Libya"),
+             PAIR(TimeZone, Met, "MET"),
+             PAIR(TimeZone, Mst, "MST"),
+             PAIR(TimeZone, Mst7Mdt, "MST7MDT"),
+             PAIR(TimeZone, Navajo, "Navajo"),
+             PAIR(TimeZone, Nz, "NZ"),
+             PAIR(TimeZone, NzChat, "NZ-CHAT"),
+             PAIR(TimeZone, Poland, "Poland"),
+             PAIR(TimeZone, Portugal, "Portugal"),
+             PAIR(TimeZone, Prc, "PRC"),
+             PAIR(TimeZone, Pst8Pdt, "PST8PDT"),
+             PAIR(TimeZone, Roc, "ROC"),
+             PAIR(TimeZone, Rok, "ROK"),
+             PAIR(TimeZone, Singapore, "Singapore"),
+             PAIR(TimeZone, Turkey, "Turkey"),
+             PAIR(TimeZone, Uct, "UCT"),
+             PAIR(TimeZone, Universal, "Universal"),
+             PAIR(TimeZone, Utc, "UTC"),
+             PAIR(TimeZone, WSu, "W-SU"),
+             PAIR(TimeZone, Wet, "WET"),
+             PAIR(TimeZone, Zulu, "Zulu"),
+         }});
+    translations->insert({Settings::EnumMetadata<Settings::AudioMode>::Index(),
+                          {
+                              PAIR(AudioMode, Mono, "Mono"),
+                              PAIR(AudioMode, Stereo, "Stereo"),
+                              PAIR(AudioMode, Surround, "Surround"),
+                          }});
+    translations->insert({Settings::EnumMetadata<Settings::MemoryLayout>::Index(),
+                          {
+                              PAIR(MemoryLayout, Memory_4Gb, "4GB DRAM (Default)"),
+                              PAIR(MemoryLayout, Memory_6Gb, "6GB DRAM (Unsafe)"),
+                              PAIR(MemoryLayout, Memory_8Gb, "8GB DRAM (Unsafe)"),
+                          }});
+
+#undef PAIR
+#undef CTX_PAIR
+
+    return translations;
+}
+} // namespace ConfigurationShared
diff --git a/src/yuzu/configuration/shared_translation.h b/src/yuzu/configuration/shared_translation.h
new file mode 100644
index 0000000000..99a0e808ca
--- /dev/null
+++ b/src/yuzu/configuration/shared_translation.h
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <typeindex>
+#include <utility>
+#include <vector>
+#include <QString>
+#include "common/common_types.h"
+
+class QWidget;
+
+namespace ConfigurationShared {
+using TranslationMap = std::map<u32, std::pair<QString, QString>>;
+using ComboboxTranslations = std::vector<std::pair<u32, QString>>;
+using ComboboxTranslationMap = std::map<u32, ComboboxTranslations>;
+
+std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent);
+
+std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent);
+
+} // namespace ConfigurationShared
diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp
new file mode 100644
index 0000000000..bdb38c8ea5
--- /dev/null
+++ b/src/yuzu/configuration/shared_widget.cpp
@@ -0,0 +1,642 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "yuzu/configuration/shared_widget.h"
+
+#include <functional>
+#include <limits>
+#include <typeindex>
+#include <typeinfo>
+#include <utility>
+#include <vector>
+
+#include <QAbstractButton>
+#include <QAbstractSlider>
+#include <QBoxLayout>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QDateTime>
+#include <QDateTimeEdit>
+#include <QIcon>
+#include <QLabel>
+#include <QLayout>
+#include <QLineEdit>
+#include <QObject>
+#include <QPushButton>
+#include <QRegularExpression>
+#include <QSizePolicy>
+#include <QSlider>
+#include <QSpinBox>
+#include <QStyle>
+#include <QValidator>
+#include <QVariant>
+#include <QtCore/qglobal.h>
+#include <QtCore/qobjectdefs.h>
+#include <fmt/core.h>
+#include <qglobal.h>
+#include <qnamespace.h>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "common/settings.h"
+#include "common/settings_common.h"
+#include "yuzu/configuration/shared_translation.h"
+
+namespace ConfigurationShared {
+
+static int restore_button_count = 0;
+
+static std::string RelevantDefault(const Settings::BasicSetting& setting) {
+    return Settings::IsConfiguringGlobal() ? setting.DefaultToString() : setting.ToStringGlobal();
+}
+
+static QString DefaultSuffix(QWidget* parent, Settings::BasicSetting& setting) {
+    const auto tr = [parent](const char* text, const char* context) {
+        return parent->tr(text, context);
+    };
+
+    if ((setting.Specialization() & Settings::SpecializationAttributeMask) ==
+        Settings::Specialization::Percentage) {
+        std::string context{fmt::format("{} percentage (e.g. 50%)", setting.GetLabel())};
+        return tr("%", context.c_str());
+    }
+
+    return QStringLiteral("");
+}
+
+QPushButton* Widget::CreateRestoreGlobalButton(bool using_global, QWidget* parent) {
+    restore_button_count++;
+
+    QStyle* style = parent->style();
+    QIcon* icon = new QIcon(style->standardIcon(QStyle::SP_LineEditClearButton));
+    QPushButton* restore_button = new QPushButton(*icon, QStringLiteral(""), parent);
+    restore_button->setObjectName(QStringLiteral("RestoreButton%1").arg(restore_button_count));
+    restore_button->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+
+    // Workaround for dark theme causing min-width to be much larger than 0
+    restore_button->setStyleSheet(
+        QStringLiteral("QAbstractButton#%1 { min-width: 0px }").arg(restore_button->objectName()));
+
+    QSizePolicy sp_retain = restore_button->sizePolicy();
+    sp_retain.setRetainSizeWhenHidden(true);
+    restore_button->setSizePolicy(sp_retain);
+
+    restore_button->setEnabled(!using_global);
+    restore_button->setVisible(!using_global);
+
+    return restore_button;
+}
+
+QLabel* Widget::CreateLabel(const QString& text) {
+    QLabel* qt_label = new QLabel(text, this->parent);
+    qt_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+    return qt_label;
+}
+
+QWidget* Widget::CreateCheckBox(Settings::BasicSetting* bool_setting, const QString& label,
+                                std::function<std::string()>& serializer,
+                                std::function<void()>& restore_func,
+                                const std::function<void()>& touch) {
+    checkbox = new QCheckBox(label, this);
+    checkbox->setCheckState(bool_setting->ToString() == "true" ? Qt::CheckState::Checked
+                                                               : Qt::CheckState::Unchecked);
+    checkbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+    if (!bool_setting->Save() && !Settings::IsConfiguringGlobal() && runtime_lock) {
+        checkbox->setEnabled(false);
+    }
+
+    serializer = [this]() {
+        return checkbox->checkState() == Qt::CheckState::Checked ? "true" : "false";
+    };
+
+    restore_func = [this, bool_setting]() {
+        checkbox->setCheckState(RelevantDefault(*bool_setting) == "true" ? Qt::Checked
+                                                                         : Qt::Unchecked);
+    };
+
+    if (!Settings::IsConfiguringGlobal()) {
+        QObject::connect(checkbox, &QCheckBox::clicked, [touch]() { touch(); });
+    }
+
+    return checkbox;
+}
+
+QWidget* Widget::CreateCombobox(std::function<std::string()>& serializer,
+                                std::function<void()>& restore_func,
+                                const std::function<void()>& touch) {
+    const auto type = setting.EnumIndex();
+
+    combobox = new QComboBox(this);
+    combobox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+    const ComboboxTranslations* enumeration{nullptr};
+    if (combobox_enumerations.contains(type)) {
+        enumeration = &combobox_enumerations.at(type);
+        for (const auto& [id, name] : *enumeration) {
+            combobox->addItem(name);
+        }
+    } else {
+        return combobox;
+    }
+
+    const auto find_index = [=](u32 value) -> int {
+        for (u32 i = 0; i < enumeration->size(); i++) {
+            if (enumeration->at(i).first == value) {
+                return i;
+            }
+        }
+        return -1;
+    };
+
+    const u32 setting_value = std::stoi(setting.ToString());
+    combobox->setCurrentIndex(find_index(setting_value));
+
+    serializer = [this, enumeration]() {
+        int current = combobox->currentIndex();
+        return std::to_string(enumeration->at(current).first);
+    };
+
+    restore_func = [this, find_index]() {
+        const u32 global_value = std::stoi(RelevantDefault(setting));
+        combobox->setCurrentIndex(find_index(global_value));
+    };
+
+    if (!Settings::IsConfiguringGlobal()) {
+        QObject::connect(combobox, QOverload<int>::of(&QComboBox::activated),
+                         [touch]() { touch(); });
+    }
+
+    return combobox;
+}
+
+QWidget* Widget::CreateLineEdit(std::function<std::string()>& serializer,
+                                std::function<void()>& restore_func,
+                                const std::function<void()>& touch, bool managed) {
+    const QString text = QString::fromStdString(setting.ToString());
+    line_edit = new QLineEdit(this);
+    line_edit->setText(text);
+
+    serializer = [this]() { return line_edit->text().toStdString(); };
+
+    if (!managed) {
+        return line_edit;
+    }
+
+    restore_func = [this]() {
+        line_edit->setText(QString::fromStdString(RelevantDefault(setting)));
+    };
+
+    if (!Settings::IsConfiguringGlobal()) {
+        QObject::connect(line_edit, &QLineEdit::textChanged, [touch]() { touch(); });
+    }
+
+    return line_edit;
+}
+
+QWidget* Widget::CreateSlider(bool reversed, float multiplier, const QString& given_suffix,
+                              std::function<std::string()>& serializer,
+                              std::function<void()>& restore_func,
+                              const std::function<void()>& touch) {
+    if (!setting.Ranged()) {
+        LOG_ERROR(Frontend, "\"{}\" is not a ranged setting, but a slider was requested.",
+                  setting.GetLabel());
+        return nullptr;
+    }
+
+    QWidget* container = new QWidget(this);
+    QHBoxLayout* layout = new QHBoxLayout(container);
+
+    slider = new QSlider(Qt::Horizontal, this);
+    QLabel* feedback = new QLabel(this);
+
+    layout->addWidget(slider);
+    layout->addWidget(feedback);
+
+    container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+    layout->setContentsMargins(0, 0, 0, 0);
+
+    int max_val = std::stoi(setting.MaxVal());
+
+    QString suffix =
+        given_suffix == QStringLiteral("") ? DefaultSuffix(this, setting) : given_suffix;
+
+    const QString use_format = QStringLiteral("%1").append(suffix);
+
+    QObject::connect(slider, &QAbstractSlider::valueChanged, [=](int value) {
+        int present = (reversed ? max_val - value : value) * multiplier + 0.5f;
+        feedback->setText(use_format.arg(QVariant::fromValue(present).value<QString>()));
+    });
+
+    slider->setMinimum(std::stoi(setting.MinVal()));
+    slider->setMaximum(max_val);
+    slider->setValue(std::stoi(setting.ToString()));
+
+    slider->setInvertedAppearance(reversed);
+
+    serializer = [this]() { return std::to_string(slider->value()); };
+    restore_func = [this]() { slider->setValue(std::stoi(RelevantDefault(setting))); };
+
+    if (!Settings::IsConfiguringGlobal()) {
+        QObject::connect(slider, &QAbstractSlider::actionTriggered, [touch]() { touch(); });
+    }
+
+    return container;
+}
+
+QWidget* Widget::CreateSpinBox(const QString& given_suffix,
+                               std::function<std::string()>& serializer,
+                               std::function<void()>& restore_func,
+                               const std::function<void()>& touch) {
+    const int min_val =
+        setting.Ranged() ? std::stoi(setting.MinVal()) : std::numeric_limits<int>::min();
+    const int max_val =
+        setting.Ranged() ? std::stoi(setting.MaxVal()) : std::numeric_limits<int>::max();
+    const int default_val = std::stoi(setting.ToString());
+
+    QString suffix =
+        given_suffix == QStringLiteral("") ? DefaultSuffix(this, setting) : given_suffix;
+
+    spinbox = new QSpinBox(this);
+    spinbox->setRange(min_val, max_val);
+    spinbox->setValue(default_val);
+    spinbox->setSuffix(suffix);
+    spinbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+    serializer = [this]() { return std::to_string(spinbox->value()); };
+
+    restore_func = [this]() {
+        auto value{std::stol(RelevantDefault(setting))};
+        spinbox->setValue(value);
+    };
+
+    if (!Settings::IsConfiguringGlobal()) {
+        QObject::connect(spinbox, QOverload<int>::of(&QSpinBox::valueChanged), [this, touch]() {
+            if (spinbox->value() != std::stoi(setting.ToStringGlobal())) {
+                touch();
+            }
+        });
+    }
+
+    return spinbox;
+}
+
+QWidget* Widget::CreateHexEdit(std::function<std::string()>& serializer,
+                               std::function<void()>& restore_func,
+                               const std::function<void()>& touch) {
+    auto* data_component = CreateLineEdit(serializer, restore_func, touch, false);
+    if (data_component == nullptr) {
+        return nullptr;
+    }
+
+    auto to_hex = [=](const std::string& input) {
+        return QString::fromStdString(fmt::format("{:08x}", std::stoul(input)));
+    };
+
+    QRegularExpressionValidator* regex = new QRegularExpressionValidator(
+        QRegularExpression{QStringLiteral("^[0-9a-fA-F]{0,8}$")}, line_edit);
+
+    const QString default_val = to_hex(setting.ToString());
+
+    line_edit->setText(default_val);
+    line_edit->setMaxLength(8);
+    line_edit->setValidator(regex);
+
+    auto hex_to_dec = [this]() -> std::string {
+        return std::to_string(std::stoul(line_edit->text().toStdString(), nullptr, 16));
+    };
+
+    serializer = [hex_to_dec]() { return hex_to_dec(); };
+
+    restore_func = [this, to_hex]() { line_edit->setText(to_hex(RelevantDefault(setting))); };
+
+    if (!Settings::IsConfiguringGlobal()) {
+
+        QObject::connect(line_edit, &QLineEdit::textChanged, [touch]() { touch(); });
+    }
+
+    return line_edit;
+}
+
+QWidget* Widget::CreateDateTimeEdit(bool disabled, bool restrict,
+                                    std::function<std::string()>& serializer,
+                                    std::function<void()>& restore_func,
+                                    const std::function<void()>& touch) {
+    const long long current_time = QDateTime::currentSecsSinceEpoch();
+    const s64 the_time = disabled ? current_time : std::stoll(setting.ToString());
+    const auto default_val = QDateTime::fromSecsSinceEpoch(the_time);
+
+    date_time_edit = new QDateTimeEdit(this);
+    date_time_edit->setDateTime(default_val);
+    date_time_edit->setMinimumDateTime(QDateTime::fromSecsSinceEpoch(0));
+    date_time_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+    serializer = [this]() { return std::to_string(date_time_edit->dateTime().toSecsSinceEpoch()); };
+
+    auto get_clear_val = [this, restrict, current_time]() {
+        return QDateTime::fromSecsSinceEpoch([this, restrict, current_time]() {
+            if (restrict && checkbox->checkState() == Qt::Checked) {
+                return std::stoll(RelevantDefault(setting));
+            }
+            return current_time;
+        }());
+    };
+
+    restore_func = [this, get_clear_val]() { date_time_edit->setDateTime(get_clear_val()); };
+
+    if (!Settings::IsConfiguringGlobal()) {
+        QObject::connect(date_time_edit, &QDateTimeEdit::editingFinished,
+                         [this, get_clear_val, touch]() {
+                             if (date_time_edit->dateTime() != get_clear_val()) {
+                                 touch();
+                             }
+                         });
+    }
+
+    return date_time_edit;
+}
+
+void Widget::SetupComponent(const QString& label, std::function<void()>& load_func, bool managed,
+                            RequestType request, float multiplier,
+                            Settings::BasicSetting* other_setting, const QString& suffix) {
+    created = true;
+    const auto type = setting.TypeId();
+
+    QLayout* layout = new QHBoxLayout(this);
+    layout->setContentsMargins(0, 0, 0, 0);
+
+    if (other_setting == nullptr) {
+        other_setting = setting.PairedSetting();
+    }
+
+    const bool require_checkbox =
+        other_setting != nullptr && other_setting->TypeId() == typeid(bool);
+
+    if (other_setting != nullptr && other_setting->TypeId() != typeid(bool)) {
+        LOG_WARNING(
+            Frontend,
+            "Extra setting \"{}\" specified but is not bool, refusing to create checkbox for it.",
+            other_setting->GetLabel());
+    }
+
+    std::function<std::string()> checkbox_serializer = []() -> std::string { return {}; };
+    std::function<void()> checkbox_restore_func = []() {};
+
+    std::function<void()> touch = []() {};
+    std::function<std::string()> serializer = []() -> std::string { return {}; };
+    std::function<void()> restore_func = []() {};
+
+    QWidget* data_component{nullptr};
+
+    request = [&]() {
+        if (request != RequestType::Default) {
+            return request;
+        }
+        switch (setting.Specialization() & Settings::SpecializationTypeMask) {
+        case Settings::Specialization::Default:
+            return RequestType::Default;
+        case Settings::Specialization::Time:
+            return RequestType::DateTimeEdit;
+        case Settings::Specialization::Hex:
+            return RequestType::HexEdit;
+        case Settings::Specialization::RuntimeList:
+            managed = false;
+            [[fallthrough]];
+        case Settings::Specialization::List:
+            return RequestType::ComboBox;
+        case Settings::Specialization::Scalar:
+            return RequestType::Slider;
+        case Settings::Specialization::Countable:
+            return RequestType::SpinBox;
+        default:
+            break;
+        }
+        return request;
+    }();
+
+    if (!Settings::IsConfiguringGlobal() && managed) {
+        restore_button = CreateRestoreGlobalButton(setting.UsingGlobal(), this);
+
+        touch = [this]() {
+            LOG_DEBUG(Frontend, "Enabling custom setting for \"{}\"", setting.GetLabel());
+            restore_button->setEnabled(true);
+            restore_button->setVisible(true);
+        };
+    }
+
+    if (require_checkbox) {
+        QWidget* lhs =
+            CreateCheckBox(other_setting, label, checkbox_serializer, checkbox_restore_func, touch);
+        layout->addWidget(lhs);
+    } else if (setting.TypeId() != typeid(bool)) {
+        QLabel* qt_label = CreateLabel(label);
+        layout->addWidget(qt_label);
+    }
+
+    if (setting.TypeId() == typeid(bool)) {
+        data_component = CreateCheckBox(&setting, label, serializer, restore_func, touch);
+    } else if (setting.IsEnum()) {
+        data_component = CreateCombobox(serializer, restore_func, touch);
+    } else if (type == typeid(u32) || type == typeid(int) || type == typeid(u16) ||
+               type == typeid(s64) || type == typeid(u8)) {
+        switch (request) {
+        case RequestType::Slider:
+        case RequestType::ReverseSlider:
+            data_component = CreateSlider(request == RequestType::ReverseSlider, multiplier, suffix,
+                                          serializer, restore_func, touch);
+            break;
+        case RequestType::Default:
+        case RequestType::LineEdit:
+            data_component = CreateLineEdit(serializer, restore_func, touch);
+            break;
+        case RequestType::DateTimeEdit:
+            data_component = CreateDateTimeEdit(other_setting->ToString() != "true", true,
+                                                serializer, restore_func, touch);
+            break;
+        case RequestType::SpinBox:
+            data_component = CreateSpinBox(suffix, serializer, restore_func, touch);
+            break;
+        case RequestType::HexEdit:
+            data_component = CreateHexEdit(serializer, restore_func, touch);
+            break;
+        case RequestType::ComboBox:
+            data_component = CreateCombobox(serializer, restore_func, touch);
+            break;
+        default:
+            UNIMPLEMENTED();
+        }
+    } else if (type == typeid(std::string)) {
+        switch (request) {
+        case RequestType::Default:
+        case RequestType::LineEdit:
+            data_component = CreateLineEdit(serializer, restore_func, touch);
+            break;
+        case RequestType::ComboBox:
+            data_component = CreateCombobox(serializer, restore_func, touch);
+            break;
+        default:
+            UNIMPLEMENTED();
+        }
+    }
+
+    if (data_component == nullptr) {
+        LOG_ERROR(Frontend, "Failed to create widget for \"{}\"", setting.GetLabel());
+        created = false;
+        return;
+    }
+
+    layout->addWidget(data_component);
+
+    if (!managed) {
+        return;
+    }
+
+    if (Settings::IsConfiguringGlobal()) {
+        load_func = [this, serializer, checkbox_serializer, require_checkbox, other_setting]() {
+            if (require_checkbox && other_setting->UsingGlobal()) {
+                other_setting->LoadString(checkbox_serializer());
+            }
+            if (setting.UsingGlobal()) {
+                setting.LoadString(serializer());
+            }
+        };
+    } else {
+        layout->addWidget(restore_button);
+
+        QObject::connect(restore_button, &QAbstractButton::clicked,
+                         [this, restore_func, checkbox_restore_func](bool) {
+                             LOG_DEBUG(Frontend, "Restore global state for \"{}\"",
+                                       setting.GetLabel());
+
+                             restore_button->setEnabled(false);
+                             restore_button->setVisible(false);
+
+                             checkbox_restore_func();
+                             restore_func();
+                         });
+
+        load_func = [this, serializer, require_checkbox, checkbox_serializer, other_setting]() {
+            bool using_global = !restore_button->isEnabled();
+            setting.SetGlobal(using_global);
+            if (!using_global) {
+                setting.LoadString(serializer());
+            }
+            if (require_checkbox) {
+                other_setting->SetGlobal(using_global);
+                if (!using_global) {
+                    other_setting->LoadString(checkbox_serializer());
+                }
+            }
+        };
+    }
+
+    if (other_setting != nullptr) {
+        const auto reset = [restore_func, data_component](int state) {
+            data_component->setEnabled(state == Qt::Checked);
+            if (state != Qt::Checked) {
+                restore_func();
+            }
+        };
+        connect(checkbox, &QCheckBox::stateChanged, reset);
+        reset(checkbox->checkState());
+    }
+}
+
+bool Widget::Valid() const {
+    return created;
+}
+
+Widget::~Widget() = default;
+
+Widget::Widget(Settings::BasicSetting* setting_, const TranslationMap& translations_,
+               const ComboboxTranslationMap& combobox_translations_, QWidget* parent_,
+               bool runtime_lock_, std::vector<std::function<void(bool)>>& apply_funcs_,
+               RequestType request, bool managed, float multiplier,
+               Settings::BasicSetting* other_setting, const QString& suffix)
+    : QWidget(parent_), parent{parent_}, translations{translations_},
+      combobox_enumerations{combobox_translations_}, setting{*setting_}, apply_funcs{apply_funcs_},
+      runtime_lock{runtime_lock_} {
+    if (!Settings::IsConfiguringGlobal() && !setting.Switchable()) {
+        LOG_DEBUG(Frontend, "\"{}\" is not switchable, skipping...", setting.GetLabel());
+        return;
+    }
+
+    const int id = setting.Id();
+
+    const auto [label, tooltip] = [&]() {
+        const auto& setting_label = setting.GetLabel();
+        if (translations.contains(id)) {
+            return std::pair{translations.at(id).first, translations.at(id).second};
+        }
+        LOG_WARNING(Frontend, "Translation table lacks entry for \"{}\"", setting_label);
+        return std::pair{QString::fromStdString(setting_label), QStringLiteral("")};
+    }();
+
+    if (label == QStringLiteral("")) {
+        LOG_DEBUG(Frontend, "Translation table has empty entry for \"{}\", skipping...",
+                  setting.GetLabel());
+        return;
+    }
+
+    std::function<void()> load_func = []() {};
+
+    SetupComponent(label, load_func, managed, request, multiplier, other_setting, suffix);
+
+    if (!created) {
+        LOG_WARNING(Frontend, "No widget was created for \"{}\"", setting.GetLabel());
+        return;
+    }
+
+    apply_funcs.push_back([load_func, setting_](bool powered_on) {
+        if (setting_->RuntimeModfiable() || !powered_on) {
+            load_func();
+        }
+    });
+
+    bool enable = runtime_lock || setting.RuntimeModfiable();
+    if (setting.Switchable() && Settings::IsConfiguringGlobal() && !runtime_lock) {
+        enable &= setting.UsingGlobal();
+    }
+    this->setEnabled(enable);
+
+    this->setToolTip(tooltip);
+}
+
+Builder::Builder(QWidget* parent_, bool runtime_lock_)
+    : translations{InitializeTranslations(parent_)},
+      combobox_translations{ComboboxEnumeration(parent_)}, parent{parent_}, runtime_lock{
+                                                                                runtime_lock_} {}
+
+Builder::~Builder() = default;
+
+Widget* Builder::BuildWidget(Settings::BasicSetting* setting,
+                             std::vector<std::function<void(bool)>>& apply_funcs,
+                             RequestType request, bool managed, float multiplier,
+                             Settings::BasicSetting* other_setting, const QString& suffix) const {
+    if (!Settings::IsConfiguringGlobal() && !setting->Switchable()) {
+        return nullptr;
+    }
+
+    if (setting->Specialization() == Settings::Specialization::Paired) {
+        LOG_DEBUG(Frontend, "\"{}\" has specialization Paired: ignoring", setting->GetLabel());
+        return nullptr;
+    }
+
+    return new Widget(setting, *translations, *combobox_translations, parent, runtime_lock,
+                      apply_funcs, request, managed, multiplier, other_setting, suffix);
+}
+
+Widget* Builder::BuildWidget(Settings::BasicSetting* setting,
+                             std::vector<std::function<void(bool)>>& apply_funcs,
+                             Settings::BasicSetting* other_setting, RequestType request,
+                             const QString& suffix) const {
+    return BuildWidget(setting, apply_funcs, request, true, 1.0f, other_setting, suffix);
+}
+
+const ComboboxTranslationMap& Builder::ComboboxTranslations() const {
+    return *combobox_translations;
+}
+
+} // namespace ConfigurationShared
diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h
new file mode 100644
index 0000000000..e64693bab3
--- /dev/null
+++ b/src/yuzu/configuration/shared_widget.h
@@ -0,0 +1,161 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+#include <QString>
+#include <QStringLiteral>
+#include <QWidget>
+#include <qobjectdefs.h>
+#include "yuzu/configuration/shared_translation.h"
+
+class QCheckBox;
+class QComboBox;
+class QDateTimeEdit;
+class QLabel;
+class QLineEdit;
+class QObject;
+class QPushButton;
+class QSlider;
+class QSpinBox;
+
+namespace Settings {
+class BasicSetting;
+} // namespace Settings
+
+namespace ConfigurationShared {
+
+enum class RequestType {
+    Default,
+    ComboBox,
+    SpinBox,
+    Slider,
+    ReverseSlider,
+    LineEdit,
+    HexEdit,
+    DateTimeEdit,
+    MaxEnum,
+};
+
+class Widget : public QWidget {
+    Q_OBJECT
+
+public:
+    /**
+     * @param setting The primary Setting to create the Widget for
+     * @param translations Map of translations to display on the left side label/checkbox
+     * @param combobox_translations Map of translations for enumerating combo boxes
+     * @param parent Qt parent
+     * @param runtime_lock Emulated guest powered on state, for use on settings that should be
+     * configured during guest execution
+     * @param apply_funcs_ List to append, functions to run to apply the widget state to the setting
+     * @param request What type of data representation component to create -- not always respected
+     * for the Setting data type
+     * @param managed Set true if the caller will set up component data and handling
+     * @param multiplier Value to multiply the slider feedback label
+     * @param other_setting Second setting to modify, to replace the label with a checkbox
+     * @param suffix Set to specify formats for Slider feedback labels or SpinBox
+     */
+    explicit Widget(Settings::BasicSetting* setting, const TranslationMap& translations,
+                    const ComboboxTranslationMap& combobox_translations, QWidget* parent,
+                    bool runtime_lock, std::vector<std::function<void(bool)>>& apply_funcs_,
+                    RequestType request = RequestType::Default, bool managed = true,
+                    float multiplier = 1.0f, Settings::BasicSetting* other_setting = nullptr,
+                    const QString& suffix = QStringLiteral(""));
+    virtual ~Widget();
+
+    /**
+     * @returns True if the Widget successfully created the components for the setting
+     */
+    bool Valid() const;
+
+    /**
+     * Creates a button to appear when a setting has been modified. This exists for custom
+     * configurations and wasn't designed to work for the global configuration. It has public access
+     * for settings that need to be unmanaged but can be custom.
+     *
+     * @param using_global The global state of the setting this button is for
+     * @param parent QWidget parent
+     */
+    [[nodiscard]] static QPushButton* CreateRestoreGlobalButton(bool using_global, QWidget* parent);
+
+    // Direct handles to sub components created
+    QPushButton* restore_button{}; ///< Restore button for custom configurations
+    QLineEdit* line_edit{};        ///< QLineEdit, used for LineEdit and HexEdit
+    QSpinBox* spinbox{};
+    QCheckBox* checkbox{};
+    QSlider* slider{};
+    QComboBox* combobox{};
+    QDateTimeEdit* date_time_edit{};
+
+private:
+    void SetupComponent(const QString& label, std::function<void()>& load_func, bool managed,
+                        RequestType request, float multiplier,
+                        Settings::BasicSetting* other_setting, const QString& suffix);
+
+    QLabel* CreateLabel(const QString& text);
+    QWidget* CreateCheckBox(Settings::BasicSetting* bool_setting, const QString& label,
+                            std::function<std::string()>& serializer,
+                            std::function<void()>& restore_func,
+                            const std::function<void()>& touch);
+
+    QWidget* CreateCombobox(std::function<std::string()>& serializer,
+                            std::function<void()>& restore_func,
+                            const std::function<void()>& touch);
+    QWidget* CreateLineEdit(std::function<std::string()>& serializer,
+                            std::function<void()>& restore_func, const std::function<void()>& touch,
+                            bool managed = true);
+    QWidget* CreateHexEdit(std::function<std::string()>& serializer,
+                           std::function<void()>& restore_func, const std::function<void()>& touch);
+    QWidget* CreateSlider(bool reversed, float multiplier, const QString& suffix,
+                          std::function<std::string()>& serializer,
+                          std::function<void()>& restore_func, const std::function<void()>& touch);
+    QWidget* CreateDateTimeEdit(bool disabled, bool restrict,
+                                std::function<std::string()>& serializer,
+                                std::function<void()>& restore_func,
+                                const std::function<void()>& touch);
+    QWidget* CreateSpinBox(const QString& suffix, std::function<std::string()>& serializer,
+                           std::function<void()>& restore_func, const std::function<void()>& touch);
+
+    QWidget* parent;
+    const TranslationMap& translations;
+    const ComboboxTranslationMap& combobox_enumerations;
+    Settings::BasicSetting& setting;
+    std::vector<std::function<void(bool)>>& apply_funcs;
+
+    bool created{false};
+    bool runtime_lock{false};
+};
+
+class Builder {
+public:
+    explicit Builder(QWidget* parent, bool runtime_lock);
+    ~Builder();
+
+    Widget* BuildWidget(Settings::BasicSetting* setting,
+                        std::vector<std::function<void(bool)>>& apply_funcs,
+                        RequestType request = RequestType::Default, bool managed = true,
+                        float multiplier = 1.0f, Settings::BasicSetting* other_setting = nullptr,
+                        const QString& suffix = QStringLiteral("")) const;
+
+    Widget* BuildWidget(Settings::BasicSetting* setting,
+                        std::vector<std::function<void(bool)>>& apply_funcs,
+                        Settings::BasicSetting* other_setting,
+                        RequestType request = RequestType::Default,
+                        const QString& suffix = QStringLiteral("")) const;
+
+    const ComboboxTranslationMap& ComboboxTranslations() const;
+
+private:
+    std::unique_ptr<TranslationMap> translations;
+    std::unique_ptr<ComboboxTranslationMap> combobox_translations;
+
+    QWidget* parent;
+    const bool runtime_lock;
+};
+
+} // namespace ConfigurationShared
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 6cd557c294..97ae9e49a2 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -24,6 +24,7 @@
 #include "applets/qt_software_keyboard.h"
 #include "applets/qt_web_browser.h"
 #include "common/nvidia_flags.h"
+#include "common/settings_enums.h"
 #include "configuration/configure_input.h"
 #include "configuration/configure_per_game.h"
 #include "configuration/configure_tas.h"
@@ -1095,10 +1096,9 @@ void GMainWindow::InitializeWidgets() {
     aa_status_button->setFocusPolicy(Qt::NoFocus);
     connect(aa_status_button, &QPushButton::clicked, [&] {
         auto aa_mode = Settings::values.anti_aliasing.GetValue();
-        if (aa_mode == Settings::AntiAliasing::LastAA) {
+        aa_mode = static_cast<Settings::AntiAliasing>(static_cast<u32>(aa_mode) + 1);
+        if (aa_mode == Settings::AntiAliasing::MaxEnum) {
             aa_mode = Settings::AntiAliasing::None;
-        } else {
-            aa_mode = static_cast<Settings::AntiAliasing>(static_cast<u32>(aa_mode) + 1);
         }
         Settings::values.anti_aliasing.SetValue(aa_mode);
         aa_status_button->setChecked(true);
@@ -1183,7 +1183,7 @@ void GMainWindow::InitializeWidgets() {
                 QMenu context_menu;
 
                 for (auto const& gpu_accuracy_pair : Config::gpu_accuracy_texts_map) {
-                    if (gpu_accuracy_pair.first == Settings::GPUAccuracy::Extreme) {
+                    if (gpu_accuracy_pair.first == Settings::GpuAccuracy::Extreme) {
                         continue;
                     }
                     context_menu.addAction(gpu_accuracy_pair.second, [this, gpu_accuracy_pair] {
@@ -3651,14 +3651,14 @@ void GMainWindow::OnToggleDockedMode() {
 
 void GMainWindow::OnToggleGpuAccuracy() {
     switch (Settings::values.gpu_accuracy.GetValue()) {
-    case Settings::GPUAccuracy::High: {
-        Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::Normal);
+    case Settings::GpuAccuracy::High: {
+        Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::Normal);
         break;
     }
-    case Settings::GPUAccuracy::Normal:
-    case Settings::GPUAccuracy::Extreme:
+    case Settings::GpuAccuracy::Normal:
+    case Settings::GpuAccuracy::Extreme:
     default: {
-        Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High);
+        Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::High);
         break;
     }
     }
@@ -3702,10 +3702,9 @@ void GMainWindow::OnIncreaseVolume() {
 
 void GMainWindow::OnToggleAdaptingFilter() {
     auto filter = Settings::values.scaling_filter.GetValue();
-    if (filter == Settings::ScalingFilter::LastFilter) {
+    filter = static_cast<Settings::ScalingFilter>(static_cast<u32>(filter) + 1);
+    if (filter == Settings::ScalingFilter::MaxEnum) {
         filter = Settings::ScalingFilter::NearestNeighbor;
-    } else {
-        filter = static_cast<Settings::ScalingFilter>(static_cast<u32>(filter) + 1);
     }
     Settings::values.scaling_filter.SetValue(filter);
     filter_status_button->setChecked(true);
@@ -4071,7 +4070,7 @@ void GMainWindow::UpdateGPUAccuracyButton() {
     const auto gpu_accuracy = Settings::values.gpu_accuracy.GetValue();
     const auto gpu_accuracy_text = Config::gpu_accuracy_texts_map.find(gpu_accuracy)->second;
     gpu_accuracy_button->setText(gpu_accuracy_text.toUpper());
-    gpu_accuracy_button->setChecked(gpu_accuracy != Settings::GPUAccuracy::Normal);
+    gpu_accuracy_button->setChecked(gpu_accuracy != Settings::GpuAccuracy::Normal);
 }
 
 void GMainWindow::UpdateDockedButton() {
diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp
index d71cc23a72..a415a953f6 100644
--- a/src/yuzu/multiplayer/direct_connect.cpp
+++ b/src/yuzu/multiplayer/direct_connect.cpp
@@ -34,13 +34,14 @@ DirectConnectWindow::DirectConnectWindow(Core::System& system_, QWidget* parent)
     connect(watcher, &QFutureWatcher<void>::finished, this, &DirectConnectWindow::OnConnection);
 
     ui->nickname->setValidator(validation.GetNickname());
-    ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue());
+    ui->nickname->setText(
+        QString::fromStdString(UISettings::values.multiplayer_nickname.GetValue()));
     if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) {
         // Use yuzu Web Service user name as nickname by default
         ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
     }
     ui->ip->setValidator(validation.GetIP());
-    ui->ip->setText(UISettings::values.multiplayer_ip.GetValue());
+    ui->ip->setText(QString::fromStdString(UISettings::values.multiplayer_ip.GetValue()));
     ui->port->setValidator(validation.GetPort());
     ui->port->setText(QString::number(UISettings::values.multiplayer_port.GetValue()));
 
@@ -91,8 +92,8 @@ void DirectConnectWindow::Connect() {
     }
 
     // Store settings
-    UISettings::values.multiplayer_nickname = ui->nickname->text();
-    UISettings::values.multiplayer_ip = ui->ip->text();
+    UISettings::values.multiplayer_nickname = ui->nickname->text().toStdString();
+    UISettings::values.multiplayer_ip = ui->ip->text().toStdString();
     if (ui->port->isModified() && !ui->port->text().isEmpty()) {
         UISettings::values.multiplayer_port = ui->port->text().toInt();
     } else {
diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp
index a8faa5b248..ef364ee43a 100644
--- a/src/yuzu/multiplayer/host_room.cpp
+++ b/src/yuzu/multiplayer/host_room.cpp
@@ -55,12 +55,14 @@ HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list,
     connect(ui->host, &QPushButton::clicked, this, &HostRoomWindow::Host);
 
     // Restore the settings:
-    ui->username->setText(UISettings::values.multiplayer_room_nickname.GetValue());
+    ui->username->setText(
+        QString::fromStdString(UISettings::values.multiplayer_room_nickname.GetValue()));
     if (ui->username->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) {
         // Use yuzu Web Service user name as nickname by default
         ui->username->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue()));
     }
-    ui->room_name->setText(UISettings::values.multiplayer_room_name.GetValue());
+    ui->room_name->setText(
+        QString::fromStdString(UISettings::values.multiplayer_room_name.GetValue()));
     ui->port->setText(QString::number(UISettings::values.multiplayer_room_port.GetValue()));
     ui->max_player->setValue(UISettings::values.multiplayer_max_player.GetValue());
     int index = UISettings::values.multiplayer_host_type.GetValue();
@@ -72,7 +74,8 @@ HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list,
     if (index != -1) {
         ui->game_list->setCurrentIndex(index);
     }
-    ui->room_description->setText(UISettings::values.multiplayer_room_description.GetValue());
+    ui->room_description->setText(
+        QString::fromStdString(UISettings::values.multiplayer_room_description.GetValue()));
 }
 
 HostRoomWindow::~HostRoomWindow() = default;
@@ -218,8 +221,8 @@ void HostRoomWindow::Host() {
                      Network::NoPreferredIP, password, token);
 
         // Store settings
-        UISettings::values.multiplayer_room_nickname = ui->username->text();
-        UISettings::values.multiplayer_room_name = ui->room_name->text();
+        UISettings::values.multiplayer_room_nickname = ui->username->text().toStdString();
+        UISettings::values.multiplayer_room_name = ui->room_name->text().toStdString();
         UISettings::values.multiplayer_game_id =
             ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong();
         UISettings::values.multiplayer_max_player = ui->max_player->value();
@@ -230,7 +233,8 @@ void HostRoomWindow::Host() {
         } else {
             UISettings::values.multiplayer_room_port = Network::DefaultRoomPort;
         }
-        UISettings::values.multiplayer_room_description = ui->room_description->toPlainText();
+        UISettings::values.multiplayer_room_description =
+            ui->room_description->toPlainText().toStdString();
         ui->host->setEnabled(true);
         emit SaveConfig();
         close();
diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp
index 387f6f7c91..603e9ae3de 100644
--- a/src/yuzu/multiplayer/lobby.cpp
+++ b/src/yuzu/multiplayer/lobby.cpp
@@ -60,7 +60,8 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
     ui->room_list->setContextMenuPolicy(Qt::CustomContextMenu);
 
     ui->nickname->setValidator(validation.GetNickname());
-    ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue());
+    ui->nickname->setText(
+        QString::fromStdString(UISettings::values.multiplayer_nickname.GetValue()));
 
     // Try find the best nickname by default
     if (ui->nickname->text().isEmpty() || ui->nickname->text() == QStringLiteral("yuzu")) {
@@ -202,9 +203,9 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
     // TODO(jroweboy): disable widgets and display a connecting while we wait
 
     // Save settings
-    UISettings::values.multiplayer_nickname = ui->nickname->text();
+    UISettings::values.multiplayer_nickname = ui->nickname->text().toStdString();
     UISettings::values.multiplayer_ip =
-        proxy->data(connection_index, LobbyItemHost::HostIPRole).toString();
+        proxy->data(connection_index, LobbyItemHost::HostIPRole).value<QString>().toStdString();
     UISettings::values.multiplayer_port =
         proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt();
     emit SaveConfig();
diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp
index 2c1b547fba..f03dc01ddc 100644
--- a/src/yuzu/uisettings.cpp
+++ b/src/yuzu/uisettings.cpp
@@ -3,6 +3,18 @@
 
 #include "yuzu/uisettings.h"
 
+#ifndef CANNOT_EXPLICITLY_INSTANTIATE
+namespace Settings {
+template class Setting<bool>;
+template class Setting<std::string>;
+template class Setting<u16, true>;
+template class Setting<u32>;
+template class Setting<u8, true>;
+template class Setting<u8>;
+template class Setting<unsigned long long>;
+} // namespace Settings
+#endif
+
 namespace UISettings {
 
 const Themes themes{{
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 20a517d34a..c9c89cee49 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -14,6 +14,21 @@
 #include "common/common_types.h"
 #include "common/settings.h"
 
+using Settings::Category;
+using Settings::Setting;
+
+#ifndef CANNOT_EXPLICITLY_INSTANTIATE
+namespace Settings {
+extern template class Setting<bool>;
+extern template class Setting<std::string>;
+extern template class Setting<u16, true>;
+extern template class Setting<u32>;
+extern template class Setting<u8, true>;
+extern template class Setting<u8>;
+extern template class Setting<unsigned long long>;
+} // namespace Settings
+#endif
+
 namespace UISettings {
 
 bool IsDarkTheme();
@@ -56,6 +71,8 @@ struct GameDir {
 };
 
 struct Values {
+    Settings::Linkage linkage{1000};
+
     QByteArray geometry;
     QByteArray state;
 
@@ -64,30 +81,54 @@ struct Values {
     QByteArray gamelist_header_state;
 
     QByteArray microprofile_geometry;
-    Settings::Setting<bool> microprofile_visible{false, "microProfileDialogVisible"};
+    Setting<bool> microprofile_visible{linkage, false, "microProfileDialogVisible",
+                                       Category::UiLayout};
 
-    Settings::Setting<bool> single_window_mode{true, "singleWindowMode"};
-    Settings::Setting<bool> fullscreen{false, "fullscreen"};
-    Settings::Setting<bool> display_titlebar{true, "displayTitleBars"};
-    Settings::Setting<bool> show_filter_bar{true, "showFilterBar"};
-    Settings::Setting<bool> show_status_bar{true, "showStatusBar"};
-
-    Settings::Setting<bool> confirm_before_closing{true, "confirmClose"};
-    Settings::Setting<bool> first_start{true, "firstStart"};
-    Settings::Setting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
-    Settings::Setting<bool> mute_when_in_background{false, "muteWhenInBackground"};
-    Settings::Setting<bool> hide_mouse{true, "hideInactiveMouse"};
-    Settings::Setting<bool> controller_applet_disabled{false, "disableControllerApplet"};
+    Setting<bool> single_window_mode{linkage, true, "singleWindowMode", Category::Ui};
+    Setting<bool> fullscreen{linkage, false, "fullscreen", Category::Ui};
+    Setting<bool> display_titlebar{linkage, true, "displayTitleBars", Category::Ui};
+    Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui};
+    Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui};
 
+    Setting<bool> confirm_before_closing{
+        linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default,
+        true,    true};
+    Setting<bool> first_start{linkage, true, "firstStart", Category::Ui};
+    Setting<bool> pause_when_in_background{linkage,
+                                           false,
+                                           "pauseWhenInBackground",
+                                           Category::UiGeneral,
+                                           Settings::Specialization::Default,
+                                           true,
+                                           true};
+    Setting<bool> mute_when_in_background{
+        linkage, false, "muteWhenInBackground", Category::Ui, Settings::Specialization::Default,
+        true,    true};
+    Setting<bool> hide_mouse{
+        linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default,
+        true,    true};
+    Setting<bool> controller_applet_disabled{linkage, false, "disableControllerApplet",
+                                             Category::UiGeneral};
     // Set when Vulkan is known to crash the application
     bool has_broken_vulkan = false;
 
-    Settings::Setting<bool> select_user_on_boot{false, "select_user_on_boot"};
+    Setting<bool> select_user_on_boot{linkage,
+                                      false,
+                                      "select_user_on_boot",
+                                      Category::UiGeneral,
+                                      Settings::Specialization::Default,
+                                      true,
+                                      true};
+    Setting<bool> disable_web_applet{linkage, true, "disable_web_applet", Category::Ui};
 
     // Discord RPC
-    Settings::Setting<bool> enable_discord_presence{true, "enable_discord_presence"};
+    Setting<bool> enable_discord_presence{linkage, true, "enable_discord_presence", Category::Ui};
 
-    Settings::Setting<bool> enable_screenshot_save_as{true, "enable_screenshot_save_as"};
+    // logging
+    Setting<bool> show_console{linkage, false, "showConsole", Category::Ui};
+
+    Setting<bool> enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as",
+                                            Category::Screenshots};
 
     QString roms_path;
     QString symbols_path;
@@ -102,47 +143,46 @@ struct Values {
     // Shortcut name <Shortcut, context>
     std::vector<Shortcut> shortcuts;
 
-    Settings::Setting<uint32_t> callout_flags{0, "calloutFlags"};
+    Setting<u32> callout_flags{linkage, 0, "calloutFlags", Category::Ui};
 
     // multiplayer settings
-    Settings::Setting<QString> multiplayer_nickname{{}, "nickname"};
-    Settings::Setting<QString> multiplayer_ip{{}, "ip"};
-    Settings::SwitchableSetting<uint, true> multiplayer_port{24872, 0, UINT16_MAX, "port"};
-    Settings::Setting<QString> multiplayer_room_nickname{{}, "room_nickname"};
-    Settings::Setting<QString> multiplayer_room_name{{}, "room_name"};
-    Settings::SwitchableSetting<uint, true> multiplayer_max_player{8, 0, 8, "max_player"};
-    Settings::SwitchableSetting<uint, true> multiplayer_room_port{24872, 0, UINT16_MAX,
-                                                                  "room_port"};
-    Settings::SwitchableSetting<uint, true> multiplayer_host_type{0, 0, 1, "host_type"};
-    Settings::Setting<qulonglong> multiplayer_game_id{{}, "game_id"};
-    Settings::Setting<QString> multiplayer_room_description{{}, "room_description"};
+    Setting<std::string> multiplayer_nickname{linkage, {}, "nickname", Category::Multiplayer};
+    Setting<std::string> multiplayer_ip{linkage, {}, "ip", Category::Multiplayer};
+    Setting<u16, true> multiplayer_port{linkage,    24872,  0,
+                                        UINT16_MAX, "port", Category::Multiplayer};
+    Setting<std::string> multiplayer_room_nickname{
+        linkage, {}, "room_nickname", Category::Multiplayer};
+    Setting<std::string> multiplayer_room_name{linkage, {}, "room_name", Category::Multiplayer};
+    Setting<u8, true> multiplayer_max_player{linkage, 8, 0, 8, "max_player", Category::Multiplayer};
+    Setting<u16, true> multiplayer_room_port{linkage,    24872,       0,
+                                             UINT16_MAX, "room_port", Category::Multiplayer};
+    Setting<u8, true> multiplayer_host_type{linkage, 0, 0, 1, "host_type", Category::Multiplayer};
+    Setting<unsigned long long> multiplayer_game_id{linkage, {}, "game_id", Category::Multiplayer};
+    Setting<std::string> multiplayer_room_description{
+        linkage, {}, "room_description", Category::Multiplayer};
     std::pair<std::vector<std::string>, std::vector<std::string>> multiplayer_ban_list;
 
-    // logging
-    Settings::Setting<bool> show_console{false, "showConsole"};
-
     // Game List
-    Settings::Setting<bool> show_add_ons{true, "show_add_ons"};
-    Settings::Setting<uint32_t> game_icon_size{64, "game_icon_size"};
-    Settings::Setting<uint32_t> folder_icon_size{48, "folder_icon_size"};
-    Settings::Setting<uint8_t> row_1_text_id{3, "row_1_text_id"};
-    Settings::Setting<uint8_t> row_2_text_id{2, "row_2_text_id"};
+    Setting<bool> show_add_ons{linkage, true, "show_add_ons", Category::UiGameList};
+    Setting<u32> game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList};
+    Setting<u32> folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList};
+    Setting<u8> row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList};
+    Setting<u8> row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList};
     std::atomic_bool is_game_list_reload_pending{false};
-    Settings::Setting<bool> cache_game_list{true, "cache_game_list"};
-    Settings::Setting<bool> favorites_expanded{true, "favorites_expanded"};
+    Setting<bool> cache_game_list{linkage, true, "cache_game_list", Category::UiGameList};
+    Setting<bool> favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList};
     QVector<u64> favorited_ids;
 
     // Compatibility List
-    Settings::Setting<bool> show_compat{false, "show_compat"};
+    Setting<bool> show_compat{linkage, false, "show_compat", Category::UiGameList};
 
     // Size & File Types Column
-    Settings::Setting<bool> show_size{true, "show_size"};
-    Settings::Setting<bool> show_types{true, "show_types"};
+    Setting<bool> show_size{linkage, true, "show_size", Category::UiGameList};
+    Setting<bool> show_types{linkage, true, "show_types", Category::UiGameList};
 
     bool configuration_applied;
     bool reset_to_defaults;
     bool shortcut_already_warned{false};
-    Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"};
 };
 
 extern Values values;
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index c5bc472ca2..c42d987090 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -98,8 +98,26 @@ void Config::ReadSetting(const std::string& group, Settings::Setting<Type, range
                                                         static_cast<long>(setting.GetDefault())));
 }
 
+void Config::ReadCategory(Settings::Category category) {
+    for (const auto setting : Settings::values.linkage.by_category[category]) {
+        const char* category_name = [&]() {
+            if (category == Settings::Category::Controls) {
+                // For compatibility with older configs
+                return "ControlsGeneral";
+            } else {
+                return Settings::TranslateCategory(category);
+            }
+        }();
+        std::string setting_value =
+            sdl2_config->Get(category_name, setting->GetLabel(), setting->DefaultToString());
+        setting->LoadString(setting_value);
+    }
+}
+
 void Config::ReadValues() {
     // Controls
+    ReadCategory(Settings::Category::Controls);
+
     for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
         auto& player = Settings::values.players.GetValue()[p];
 
@@ -139,13 +157,6 @@ void Config::ReadValues() {
         player.connected = sdl2_config->GetBoolean(group, "connected", false);
     }
 
-    ReadSetting("ControlsGeneral", Settings::values.mouse_enabled);
-
-    ReadSetting("ControlsGeneral", Settings::values.touch_device);
-
-    ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled);
-
-    ReadSetting("ControlsGeneral", Settings::values.debug_pad_enabled);
     for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
         std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
         Settings::values.debug_pad_buttons[i] = sdl2_config->Get(
@@ -166,14 +177,6 @@ void Config::ReadValues() {
             Settings::values.debug_pad_analogs[i] = default_param;
     }
 
-    ReadSetting("ControlsGeneral", Settings::values.enable_raw_input);
-    ReadSetting("ControlsGeneral", Settings::values.enable_joycon_driver);
-    ReadSetting("ControlsGeneral", Settings::values.enable_procon_driver);
-    ReadSetting("ControlsGeneral", Settings::values.random_amiibo_id);
-    ReadSetting("ControlsGeneral", Settings::values.emulate_analog_keyboard);
-    ReadSetting("ControlsGeneral", Settings::values.vibration_enabled);
-    ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations);
-    ReadSetting("ControlsGeneral", Settings::values.motion_enabled);
     Settings::values.touchscreen.enabled =
         sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
     Settings::values.touchscreen.rotation_angle =
@@ -217,10 +220,24 @@ void Config::ReadValues() {
     Settings::values.touch_from_button_map_index = std::clamp(
         Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
 
-    ReadSetting("ControlsGeneral", Settings::values.udp_input_servers);
+    ReadCategory(Settings::Category::Audio);
+    ReadCategory(Settings::Category::Core);
+    ReadCategory(Settings::Category::Cpu);
+    ReadCategory(Settings::Category::CpuDebug);
+    ReadCategory(Settings::Category::CpuUnsafe);
+    ReadCategory(Settings::Category::Renderer);
+    ReadCategory(Settings::Category::RendererAdvanced);
+    ReadCategory(Settings::Category::RendererDebug);
+    ReadCategory(Settings::Category::System);
+    ReadCategory(Settings::Category::SystemAudio);
+    ReadCategory(Settings::Category::DataStorage);
+    ReadCategory(Settings::Category::Debugging);
+    ReadCategory(Settings::Category::DebuggingGraphics);
+    ReadCategory(Settings::Category::Miscellaneous);
+    ReadCategory(Settings::Category::Network);
+    ReadCategory(Settings::Category::WebService);
 
     // Data Storage
-    ReadSetting("Data Storage", Settings::values.use_virtual_sd);
     FS::SetYuzuPath(FS::YuzuPath::NANDDir,
                     sdl2_config->Get("Data Storage", "nand_directory",
                                      FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
@@ -233,124 +250,10 @@ void Config::ReadValues() {
     FS::SetYuzuPath(FS::YuzuPath::DumpDir,
                     sdl2_config->Get("Data Storage", "dump_directory",
                                      FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
-    ReadSetting("Data Storage", Settings::values.gamecard_inserted);
-    ReadSetting("Data Storage", Settings::values.gamecard_current_game);
-    ReadSetting("Data Storage", Settings::values.gamecard_path);
-
-    // System
-    ReadSetting("System", Settings::values.use_docked_mode);
-
-    ReadSetting("System", Settings::values.current_user);
-    Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0,
-                                                    Service::Account::MAX_USERS - 1);
-
-    const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false);
-    if (rng_seed_enabled) {
-        Settings::values.rng_seed.SetValue(sdl2_config->GetInteger("System", "rng_seed", 0));
-    } else {
-        Settings::values.rng_seed.SetValue(std::nullopt);
-    }
-
-    const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false);
-    if (custom_rtc_enabled) {
-        Settings::values.custom_rtc = sdl2_config->GetInteger("System", "custom_rtc", 0);
-    } else {
-        Settings::values.custom_rtc = std::nullopt;
-    }
-
-    ReadSetting("System", Settings::values.language_index);
-    ReadSetting("System", Settings::values.region_index);
-    ReadSetting("System", Settings::values.time_zone_index);
-    ReadSetting("System", Settings::values.sound_index);
-
-    // Core
-    ReadSetting("Core", Settings::values.use_multi_core);
-    ReadSetting("Core", Settings::values.use_unsafe_extended_memory_layout);
-
-    // Cpu
-    ReadSetting("Cpu", Settings::values.cpu_accuracy);
-    ReadSetting("Cpu", Settings::values.cpu_debug_mode);
-    ReadSetting("Cpu", Settings::values.cpuopt_page_tables);
-    ReadSetting("Cpu", Settings::values.cpuopt_block_linking);
-    ReadSetting("Cpu", Settings::values.cpuopt_return_stack_buffer);
-    ReadSetting("Cpu", Settings::values.cpuopt_fast_dispatcher);
-    ReadSetting("Cpu", Settings::values.cpuopt_context_elimination);
-    ReadSetting("Cpu", Settings::values.cpuopt_const_prop);
-    ReadSetting("Cpu", Settings::values.cpuopt_misc_ir);
-    ReadSetting("Cpu", Settings::values.cpuopt_reduce_misalign_checks);
-    ReadSetting("Cpu", Settings::values.cpuopt_fastmem);
-    ReadSetting("Cpu", Settings::values.cpuopt_fastmem_exclusives);
-    ReadSetting("Cpu", Settings::values.cpuopt_recompile_exclusives);
-    ReadSetting("Cpu", Settings::values.cpuopt_ignore_memory_aborts);
-    ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma);
-    ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error);
-    ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
-    ReadSetting("Cpu", Settings::values.cpuopt_unsafe_inaccurate_nan);
-    ReadSetting("Cpu", Settings::values.cpuopt_unsafe_fastmem_check);
-    ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_global_monitor);
-
-    // Renderer
-    ReadSetting("Renderer", Settings::values.renderer_backend);
-    ReadSetting("Renderer", Settings::values.async_presentation);
-    ReadSetting("Renderer", Settings::values.renderer_force_max_clock);
-    ReadSetting("Renderer", Settings::values.renderer_debug);
-    ReadSetting("Renderer", Settings::values.renderer_shader_feedback);
-    ReadSetting("Renderer", Settings::values.enable_nsight_aftermath);
-    ReadSetting("Renderer", Settings::values.disable_shader_loop_safety_checks);
-    ReadSetting("Renderer", Settings::values.vulkan_device);
-
-    ReadSetting("Renderer", Settings::values.resolution_setup);
-    ReadSetting("Renderer", Settings::values.scaling_filter);
-    ReadSetting("Renderer", Settings::values.fsr_sharpening_slider);
-    ReadSetting("Renderer", Settings::values.anti_aliasing);
-    ReadSetting("Renderer", Settings::values.fullscreen_mode);
-    ReadSetting("Renderer", Settings::values.aspect_ratio);
-    ReadSetting("Renderer", Settings::values.max_anisotropy);
-    ReadSetting("Renderer", Settings::values.use_speed_limit);
-    ReadSetting("Renderer", Settings::values.speed_limit);
-    ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
-    ReadSetting("Renderer", Settings::values.gpu_accuracy);
-    ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
-    ReadSetting("Renderer", Settings::values.vsync_mode);
-    ReadSetting("Renderer", Settings::values.shader_backend);
-    ReadSetting("Renderer", Settings::values.use_reactive_flushing);
-    ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
-    ReadSetting("Renderer", Settings::values.nvdec_emulation);
-    ReadSetting("Renderer", Settings::values.accelerate_astc);
-    ReadSetting("Renderer", Settings::values.async_astc);
-    ReadSetting("Renderer", Settings::values.astc_recompression);
-    ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
-    ReadSetting("Renderer", Settings::values.use_vulkan_driver_pipeline_cache);
-
-    ReadSetting("Renderer", Settings::values.bg_red);
-    ReadSetting("Renderer", Settings::values.bg_green);
-    ReadSetting("Renderer", Settings::values.bg_blue);
-
-    // Audio
-    ReadSetting("Audio", Settings::values.sink_id);
-    ReadSetting("Audio", Settings::values.audio_output_device_id);
-    ReadSetting("Audio", Settings::values.volume);
-
-    // Miscellaneous
-    // log_filter has a different default here than from common
-    Settings::values.log_filter =
-        sdl2_config->Get("Miscellaneous", Settings::values.log_filter.GetLabel(), "*:Trace");
-    ReadSetting("Miscellaneous", Settings::values.use_dev_keys);
 
     // Debugging
     Settings::values.record_frame_times =
         sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
-    ReadSetting("Debugging", Settings::values.dump_exefs);
-    ReadSetting("Debugging", Settings::values.dump_nso);
-    ReadSetting("Debugging", Settings::values.enable_fs_access_log);
-    ReadSetting("Debugging", Settings::values.reporting_services);
-    ReadSetting("Debugging", Settings::values.quest_flag);
-    ReadSetting("Debugging", Settings::values.use_debug_asserts);
-    ReadSetting("Debugging", Settings::values.use_auto_stub);
-    ReadSetting("Debugging", Settings::values.disable_macro_jit);
-    ReadSetting("Debugging", Settings::values.disable_macro_hle);
-    ReadSetting("Debugging", Settings::values.use_gdbstub);
-    ReadSetting("Debugging", Settings::values.gdbstub_port);
 
     const auto title_list = sdl2_config->Get("AddOns", "title_ids", "");
     std::stringstream ss(title_list);
@@ -368,15 +271,6 @@ void Config::ReadValues() {
 
         Settings::values.disabled_addons.insert_or_assign(title_id, out);
     }
-
-    // Web Service
-    ReadSetting("WebService", Settings::values.enable_telemetry);
-    ReadSetting("WebService", Settings::values.web_api_url);
-    ReadSetting("WebService", Settings::values.yuzu_username);
-    ReadSetting("WebService", Settings::values.yuzu_token);
-
-    // Network
-    ReadSetting("Network", Settings::values.network_interface);
 }
 
 void Config::Reload() {
diff --git a/src/yuzu_cmd/config.h b/src/yuzu_cmd/config.h
index 021438b17e..512591a39c 100644
--- a/src/yuzu_cmd/config.h
+++ b/src/yuzu_cmd/config.h
@@ -34,4 +34,5 @@ private:
      */
     template <typename Type, bool ranged>
     void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting);
+    void ReadCategory(Settings::Category category);
 };