diff --git a/armarx_setup/cli/config/commands.py b/armarx_setup/cli/config/commands.py
index a9323af3498eeced2943cbbffd8127be7b9bf41b..31fef8fa4b7feb324592f1b9e24675b88b55c229 100644
--- a/armarx_setup/cli/config/commands.py
+++ b/armarx_setup/cli/config/commands.py
@@ -15,6 +15,8 @@ COMMAND_GROUPS = []  # Default.
                 shell_complete=integration.list_config_option_values)
 @click.option("--global", "-g", "is_global", default=False, is_flag=True, help="Set/get/unset the global variables.")
 @click.option("--unset", "-u", default=False, is_flag=True, help="Unsets the variable.")
+@click.option("--subconfig", "-s", default=False, is_flag=True, help="Apply to whole subconfig with the name of the "
+                                                                     "variable.")
 def config(**kwargs):
     """Get or set global configurations."""
 
diff --git a/armarx_setup/cli/config/integration.py b/armarx_setup/cli/config/integration.py
index ef96290aeffd7facbe6652f74ef805f4804ea9f8..9bec5a4d508cf243f87b630513dbdd92ba2a1274 100644
--- a/armarx_setup/cli/config/integration.py
+++ b/armarx_setup/cli/config/integration.py
@@ -6,7 +6,7 @@ import typing as ty
 import rich_click as click
 
 from armarx_setup import console
-from armarx_setup.core.config import config as axii_config, BuiltInConfigVariables
+from armarx_setup.core.config import config as axii_config, BuiltInConfigVariables, Config
 from armarx_setup.cli import common, complete
 
 
@@ -24,7 +24,7 @@ def list_config_option_values(ctx, param, incomplete: str) -> ty.List[str]:
     return complete.filter_completion(possible_values, incomplete)
 
 
-def config(variable_name, variable_value=None, is_global=True, unset=False):
+def config(variable_name, variable_value=None, is_global=True, unset=False, subconfig=False):
     # A workspace must be active if global is true.
     if not is_global:
         from armarx_setup.core.workspace import Workspace
@@ -38,6 +38,11 @@ def config(variable_name, variable_value=None, is_global=True, unset=False):
             axii_config.unset(variable_name, is_global=is_global)
             console.print(f"Unset '{variable_name}' ({'global' if is_global else 'workspace-specific'}).")
             axii_config.store_config()
+        # If --subconfig was set, then the intention is to create a new subconfig.
+        elif subconfig:
+            axii_config.set(variable_name, Config(), is_global=is_global)
+            console.print(f"Create new subconfig '{variable_name}' ({'global' if is_global else 'workspace-specific'}).")
+            axii_config.store_config()
         # Otherwise print it if found.
         else:
             value = axii_config.get(variable_name, is_global=is_global)
@@ -50,7 +55,8 @@ def config(variable_name, variable_value=None, is_global=True, unset=False):
         variable_value_raw = axii_config.get(variable_name, interpret=False, is_global=is_global)
         variable_value = axii_config.get(variable_name, interpret=True, is_global=is_global)
         resolved = f" ({variable_value})" if variable_value_raw != variable_value else ""
-        console.print(f"Set '{variable_name}' ({'global' if is_global else 'workspace-specific'}) to {variable_value_raw}{resolved}.")
+        console.print(f"Set '{variable_name}' ({'global' if is_global else 'workspace-specific'}) to "
+                      f"{variable_value_raw}{resolved}.")
         axii_config.store_config()
 
 
diff --git a/armarx_setup/core/config.py b/armarx_setup/core/config.py
index e6b483aab842d1ac1db14d829661a4cb41021284..538f502f9d2bdf9855d1ffaaff6f0128bc8d7d03 100644
--- a/armarx_setup/core/config.py
+++ b/armarx_setup/core/config.py
@@ -7,6 +7,7 @@ import math
 import multiprocessing
 import os
 import typing as ty
+import shutil
 
 from xdg import xdg_config_home
 
@@ -30,11 +31,18 @@ class ConfigVariable:
     def __init__(
             self,
             name: str,
-            value_type: type
+            value_type: ty.Optional[type] = None,
+            default_value: ty.Optional[ty.Any] = None,
     ):
+        assert value_type is not None or default_value is not None, \
+            "Must supply a value_type if no default_value specified."
+
         self.name: str = name
         self.value_type: type = value_type
-        self.value: ty.Optional[value_type] = None
+        self.value: ty.Optional[value_type] = default_value
+
+        if self.value_type is None:
+            self.value_type = type(self.value)
 
     def verify_value(self, value):
         """Verify the value's format.
@@ -147,6 +155,9 @@ class Config:
 
         return out_dict
 
+    def __str__(self):
+        return self.to_dict().__str__()
+
     def has_variable(self, name: str) -> bool:
         return name in self.config_vars
 
@@ -172,6 +183,22 @@ class Config:
         del self.config_vars[name]
 
 
+class Subconfig(Config):
+    pass
+
+
+class SubconfigVariable(ConfigVariable):
+    def __init__(self, name: str):
+        default_value = Subconfig()
+        super().__init__(name=name, default_value=default_value)
+
+    def parse_value(self, value: ty.Dict[str, str]) -> Config:
+        return Subconfig.from_dict(**value)
+
+    def interpret_value(self, value):
+        return value
+
+
 class BuiltInConfigVariable(ConfigVariable):
     """Models a built-in config variable."""
 
@@ -221,7 +248,7 @@ class DefaultWorkspaceConfigVariable(BuiltInConfigVariable):
         return value
 
 
-class GitRemotePreferencesConfig(Config):
+class GitRemotePreferencesSubconfig(Config):
     """Override for a Config specific for git_remote_preferences with method
     'preference_for_host'."""
 
@@ -245,17 +272,17 @@ class GitRemotePreferencesConfig(Config):
         return "https"  # Default is HTTPS as it requires no additional setup.
 
 
-class GitRemotePreferencesConfigVariable(BuiltInConfigVariable):
+class GitRemotePreferencesSubconfigVariable(BuiltInConfigVariable):
     """Special implementation for the git_remote_preferences configuration variable."""
 
     def __init__(self):
         name = "git_remote_preferences"
-        default_value = GitRemotePreferencesConfig()
+        default_value = GitRemotePreferencesSubconfig()
         description = ""
         super().__init__(name=name, default_value=default_value, description=description)
 
     def parse_value(self, value: ty.Dict[str, str]) -> Config:
-        return GitRemotePreferencesConfig.from_dict(**value)
+        return GitRemotePreferencesSubconfig.from_dict(**value)
 
     def interpret_value(self, value):
         return value
@@ -390,7 +417,7 @@ class BuiltInConfigVariables:
 
     default_workspace = DefaultWorkspaceConfigVariable()
 
-    git_remote_preferences = GitRemotePreferencesConfigVariable()
+    git_remote_preferences = GitRemotePreferencesSubconfigVariable()
 
     update_job_number = UpdateJobNumberConfigVariable()
 
@@ -436,7 +463,10 @@ class ConfigWithBuiltIns(Config):
             if key in BuiltInConfigVariables.get_all_names():
                 cfg_var = BuiltInConfigVariables.get_by_name(key)
             else:
-                cfg_var = ConfigVariable(name=key, value_type=type(value))
+                if isinstance(value, dict):
+                    cfg_var = SubconfigVariable(name=key)
+                else:
+                    cfg_var = ConfigVariable(name=key, value_type=type(value))
             cfg_var.set_value(value, parse=True)
             config_vars[key] = cfg_var
         return cls(config_vars=config_vars)
@@ -479,6 +509,7 @@ class AxiiConfig:
 
         self.global_config_file_name = "global_config.json"
         self.global_config_file_path = os.path.join(self.config_dir, self.global_config_file_name)
+        self.global_config_backup_file_path = os.path.join(self.config_dir, "global_config_BAK.json")
         self.global_config: ConfigWithBuiltIns = ConfigWithBuiltIns()
 
         self._known_workspaces_file_name = "known_workspaces.json"
@@ -496,9 +527,11 @@ class AxiiConfig:
                     self._workspace_name = name
 
         self.has_local_config = self._is_workspace_active
-        self.local_config_dir: str | None = os.path.join(self._workspace_dir, ".axii") if self.has_local_config else None
+        self.local_config_dir: str | None = os.path.join(self._workspace_dir, ".axii") \
+            if self.has_local_config else None
         self.local_config_file_name = "config.json"
-        self.local_config_file_path: str | None = os.path.join(self.local_config_dir, self.local_config_file_name) if self.has_local_config else None
+        self.local_config_file_path: str | None = os.path.join(self.local_config_dir, self.local_config_file_name) \
+            if self.has_local_config else None
         self.local_config: Config | None = Config() if self.has_local_config else None
 
         self._build_job_number = None
@@ -604,6 +637,12 @@ class AxiiConfig:
         with open(self.global_config_file_path, "w", encoding="utf-8") as file:
             json.dump(self.global_config.to_dict(), file, indent=2)
 
+    def create_global_config_backup(self):
+        shutil.copyfile(self.global_config_file_path, self.global_config_backup_file_path)
+
+    def restore_global_config_backup(self):
+        shutil.copyfile(self.global_config_backup_file_path, self.global_config_file_path)
+
     def get(self, name, interpret: bool = True, is_global: bool = True):
         """Get the value of a variable."""
 
diff --git a/armarx_setup/core/git.py b/armarx_setup/core/git.py
index 6655083acef5935df6c7e110ec54dd71332454c6..eda138abea9358ae3934d2efaf2297fe21770ce9 100644
--- a/armarx_setup/core/git.py
+++ b/armarx_setup/core/git.py
@@ -8,7 +8,7 @@ import git
 
 from armarx_setup import console, PACKAGE_ROOT
 from armarx_setup.core import error
-from armarx_setup.core.config import axii_config, GitRemotePreferencesConfig
+from armarx_setup.core.config import axii_config, GitRemotePreferencesSubconfig
 
 
 class Symbols:
@@ -274,7 +274,7 @@ def correct_origin_url_configuration_issue(
 
     if module.update.git.code_hoster is not None:
         domain = module.update.git.code_hoster.domain()
-        grp: GitRemotePreferencesConfig = axii_config.global_config.get("git_remote_preferences")
+        grp: GitRemotePreferencesSubconfig = axii_config.global_config.get("git_remote_preferences")
         is_https = grp.preference_for_host(domain) == "https"
     else:
         # If no code hoster is defined for the module, try to guess preferred mechanism from current
diff --git a/armarx_setup/core/module/update/git.py b/armarx_setup/core/module/update/git.py
index 61fa3fdd07bfcb5d501f7a0653d1fb60a5efd872..195e57f765fed8dc9dd534087dee70f713c3c3e2 100644
--- a/armarx_setup/core/module/update/git.py
+++ b/armarx_setup/core/module/update/git.py
@@ -9,7 +9,7 @@ from armarx_setup.core import error
 from armarx_setup.core.module import common
 from armarx_setup.core.module.context import Hook
 from armarx_setup.core.util import commands
-from armarx_setup.core.config import axii_config, GitRemotePreferencesConfig
+from armarx_setup.core.config import axii_config, GitRemotePreferencesSubconfig
 
 
 git_non_interaction_env_vars = {
@@ -169,7 +169,7 @@ class Git(Hook):
         url = self.https_url
 
         if not prefer_https and self.code_hoster is not None:
-            grp: GitRemotePreferencesConfig = axii_config.get("git_remote_preferences")
+            grp: GitRemotePreferencesSubconfig = axii_config.get("git_remote_preferences")
             if grp.preference_for_host(self.code_hoster.domain()) == "ssh":
                 url = self.ssh_url
 
diff --git a/tests/e2e/test_axii_config.py b/tests/e2e/test_axii_config.py
index 9e9796ddcc1c20ac5fdf45800ac16bee2ab40673..bfb0acd14249ecf7f9743f1f8ab951055ef4f312 100644
--- a/tests/e2e/test_axii_config.py
+++ b/tests/e2e/test_axii_config.py
@@ -6,7 +6,7 @@ import os
 import pytest
 
 from armarx_setup.core import error
-from armarx_setup.core.config import axii_config
+from armarx_setup.core.config import axii_config as axii_config_raw
 from armarx_setup.core.util.commands import run
 from armarx_setup.core.workspace import Workspace
 
@@ -14,10 +14,21 @@ from tests.e2e import cmd_args, test_workspace
 
 
 variable_name = "e2e_test_var"
+nested_variable_prefix = "e2e"
+nested_variable_name = "test_var"
 variable_value = "true"
 
 
-def test_get_nonexistent_global_config_var():
+@pytest.fixture()
+def axii_config():
+    """Injecting this fixture will ensure that the actual global config is backed up and restored for e2e tests."""
+
+    axii_config_raw.create_global_config_backup()
+    yield axii_config_raw
+    axii_config_raw.restore_global_config_backup()
+
+
+def test_get_nonexistent_global_config_var(axii_config):
     """
     Test getting non-existent global config variable.
     """
@@ -35,31 +46,29 @@ def test_get_nonexistent_global_config_var():
     assert f"No such config variable '{variable_name}'." in stdout
 
 
-def test_set_global_config_var():
+def test_set_and_get_global_config_var(axii_config):
     """
-    Test setting global config variable.
+    Test setting and getting global config variable.
     """
 
     stdout = run(f"axii config --global {variable_name} {variable_value}", **cmd_args)
 
     assert stdout == f"Set '{variable_name}' (global) to {variable_value}."
 
-
-def test_get_global_config_var():
-    """
-    Test getting global config variable.
-    """
-
     stdout = run(f"axii config --global {variable_name}", **cmd_args)
 
     assert stdout == "true"
 
 
-def test_unset_global_config_var():
+def test_unset_global_config_var(axii_config):
     """
     Test unsetting global config variable.
     """
 
+    stdout = run(f"axii config --global {variable_name} {variable_value}", **cmd_args)
+
+    assert stdout == f"Set '{variable_name}' (global) to {variable_value}."
+
     stdout = run(f"axii config --global --unset {variable_name}", **cmd_args)
 
     assert stdout == f"Unset '{variable_name}' (global)."
diff --git a/tests/unit/core/test_config.py b/tests/unit/core/test_config.py
index be52ab334af9daf16f3fbdfb3f91318e67657eb1..8d5a7a63efd024f0766c0a7f6bafed5bc95b5095 100644
--- a/tests/unit/core/test_config.py
+++ b/tests/unit/core/test_config.py
@@ -9,7 +9,7 @@ from armarx_setup.core.config import AxiiConfig, Config, ConfigVariable
 from armarx_setup.core.config import ConfigWithBuiltIns, BuiltInConfigVariables, \
     BuiltInConfigVariable
 # Overrides of Config for git_remote_preferences.
-from armarx_setup.core.config import GitRemotePreferencesConfig
+from armarx_setup.core.config import GitRemotePreferencesSubconfig
 # OVerrides of ConfigVariable for build_job_number.
 from armarx_setup.core.config import BuildJobNumberConfigVariable
 
@@ -101,9 +101,9 @@ def test_interpret_git_remote_preferences():
 
     cfg = ConfigWithBuiltIns.from_dict(**cfg_dict)
 
-    git_remote_cfg_var: GitRemotePreferencesConfig = cfg.get("git_remote_preferences")
+    git_remote_cfg_var: GitRemotePreferencesSubconfig = cfg.get("git_remote_preferences")
 
-    assert type(git_remote_cfg_var) is GitRemotePreferencesConfig
+    assert type(git_remote_cfg_var) is GitRemotePreferencesSubconfig
 
     assert git_remote_cfg_var.preference_for_host("git.h2t.iar.kit.edu") == "ssh"
     assert git_remote_cfg_var.preference_for_host("gitlab.com") == "ssh"