diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml
index 390c0fd6bbbf216cef55e4579def2ac9300c6b36..4694cf697138b9589e037690b51882bb14df39c8 100644
--- a/core/config/schema/core.data_types.schema.yml
+++ b/core/config/schema/core.data_types.schema.yml
@@ -561,7 +561,7 @@ core.date_format.*:
   label: 'Date format'
   mapping:
     id:
-      type: string
+      type: machine_name
       label: 'ID'
     label:
       type: required_label
@@ -572,6 +572,15 @@ core.date_format.*:
     pattern:
       type: core_date_format_pattern.[%parent.locked]
       label: 'PHP date format'
+      constraints:
+        NotBlank: []
+        # A valid date format character must appear somewhere in the value.
+        # See https://www.php.net/manual/en/datetime.format.php
+        Regex:
+          pattern: '/[aABcdDeFgGhHiIjlLmMnNoOpPrsStTuUvwWxXyYzZ]/'
+          message: 'This is not a valid date format.'
+  constraints:
+    FullyValidatable: ~
 
 # Unlocked date formats should use the translatable type.
 core_date_format_pattern.0:
diff --git a/core/modules/system/tests/src/Kernel/DateFormatAccessControlHandlerTest.php b/core/modules/system/tests/src/Kernel/DateFormatAccessControlHandlerTest.php
index 7282826400a7db6a70086bb0ca52bc8d1f858ab8..d63f44fccb14e5a90f19b779801a6df11c519987 100644
--- a/core/modules/system/tests/src/Kernel/DateFormatAccessControlHandlerTest.php
+++ b/core/modules/system/tests/src/Kernel/DateFormatAccessControlHandlerTest.php
@@ -69,6 +69,7 @@ public function testAccess($which_user, $which_entity, $view_label_access_result
       ? ['locked' => FALSE]
       : ['locked' => TRUE];
     $entity_values['id'] = $entity_values['label'] = $this->randomMachineName();
+    $entity_values['pattern'] = 'Y-m-d';
     $entity = DateFormat::create($entity_values);
     $entity->save();
 
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/DateFormatValidationTest.php b/core/tests/Drupal/KernelTests/Core/Entity/DateFormatValidationTest.php
index 10e97012bbdb8b35cfb76a0a43dcb6688d444588..93195e4076b7867f4e448089b40d3de2178d9e24 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/DateFormatValidationTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/DateFormatValidationTest.php
@@ -27,4 +27,24 @@ protected function setUp(): void {
     $this->entity->save();
   }
 
+  /**
+   * Tests that the pattern of a date format is validated.
+   *
+   * @param string $pattern
+   *   The pattern to set.
+   * @param bool $locked
+   *   Whether the date format entity is locked or not.
+   * @param string $expected_error
+   *   The error message that should be flagged for the invalid pattern.
+   *
+   * @testWith ["q", true, "This is not a valid date format."]
+   *   ["", true, "This value should not be blank."]
+   *   ["q", false, "This is not a valid date format."]
+   *   ["", false, "This value should not be blank."]
+   */
+  public function testPatternIsValidated(string $pattern, bool $locked, string $expected_error): void {
+    $this->entity->setPattern($pattern)->set('locked', $locked);
+    $this->assertValidationErrors(['pattern' => $expected_error]);
+  }
+
 }