diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml
index d866c01b1ed14a11d22505d1475cde1844016d77..748500fca26af4db635629984e5b6f4aeacd5d75 100644
--- a/core/config/schema/core.data_types.schema.yml
+++ b/core/config/schema/core.data_types.schema.yml
@@ -114,6 +114,15 @@ _core_config_info:
     default_config_hash:
       type: string
       label: 'Default configuration hash'
+      constraints:
+        NotNull: []
+        Regex: '/^[a-zA-Z0-9\-_]+$/'
+        # The hash is a base64-encoded version of the config's SHA-256 hash. Given
+        # the deterministic length of a SHA-256 hash, and the way base64 encoding
+        # works, this is always going to be 43 characters long.
+        Length: 43
+  constraints:
+    ValidKeys: ['default_config_hash']
 
 config_object:
   type: mapping
diff --git a/core/tests/Drupal/KernelTests/Core/Config/SimpleConfigValidationTest.php b/core/tests/Drupal/KernelTests/Core/Config/SimpleConfigValidationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..74060fb35bfe20a356d65bdcea48cb8d1a419656
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Config/SimpleConfigValidationTest.php
@@ -0,0 +1,75 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\KernelTests\Core\Config;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests validation of certain elements common to all config.
+ *
+ * @group config
+ * @group Validation
+ */
+class SimpleConfigValidationTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['system'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+    $this->installConfig('system');
+  }
+
+  public function testDefaultConfigHashValidation(): void {
+    $config = $this->config('system.site');
+    $this->assertFalse($config->isNew());
+    $data = $config->get();
+    $original_hash = $data['_core']['default_config_hash'];
+    $this->assertNotEmpty($original_hash);
+
+    /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager */
+    $typed_config_manager = $this->container->get('config.typed');
+
+    // If the default_config_hash is NULL, it should be an error.
+    $data['_core']['default_config_hash'] = NULL;
+    $violations = $typed_config_manager->createFromNameAndData($config->getName(), $data)
+      ->validate();
+    $this->assertCount(1, $violations);
+    $this->assertSame('_core.default_config_hash', $violations[0]->getPropertyPath());
+    $this->assertSame('This value should not be null.', (string) $violations[0]->getMessage());
+
+    // Config hashes must be 43 characters long.
+    $data['_core']['default_config_hash'] = $original_hash . '-long';
+    $violations = $typed_config_manager->createFromNameAndData($config->getName(), $data)
+      ->validate();
+    $this->assertCount(1, $violations);
+    $this->assertSame('_core.default_config_hash', $violations[0]->getPropertyPath());
+    $this->assertSame('This value should have exactly <em class="placeholder">43</em> characters.', (string) $violations[0]->getMessage());
+
+    // Config hashes can only contain certain characters, and spaces aren't one
+    // of them. If we replace the final character of the original hash with a
+    // space, we should get an error.
+    $data['_core']['default_config_hash'] = substr($original_hash, 0, -1) . ' ';
+    $violations = $typed_config_manager->createFromNameAndData($config->getName(), $data)
+      ->validate();
+    $this->assertCount(1, $violations);
+    $this->assertSame('_core.default_config_hash', $violations[0]->getPropertyPath());
+    $this->assertSame('This value is not valid.', (string) $violations[0]->getMessage());
+
+    $data['_core']['default_config_hash'] = $original_hash;
+    $data['_core']['invalid_key'] = 'Hello';
+    $violations = $typed_config_manager->createFromNameAndData($config->getName(), $data)
+      ->validate();
+    $this->assertCount(1, $violations);
+    $this->assertSame('_core', $violations[0]->getPropertyPath());
+    $this->assertSame("'invalid_key' is not a supported key.", (string) $violations[0]->getMessage());
+  }
+
+}