diff --git a/core/.deprecation-ignore.txt b/core/.deprecation-ignore.txt
index 12772fbb55bc6ce068abe821243c77c265bc5be8..4dcdec3e433b7bb3a422df0c83c9976ba846252f 100644
--- a/core/.deprecation-ignore.txt
+++ b/core/.deprecation-ignore.txt
@@ -39,6 +39,3 @@
 %The "Drupal\\Core\\Database\\Query\\SelectExtender::hasAnyTag\(\)" method will require a new "string \.\.\. \$tags" argument in the next major version of its interface%
 %The "Drupal\\Core\\Entity\\Query\\QueryBase::hasAllTags\(\)" method will require a new "string \.\.\. \$tags" argument in the next major version of its interface%
 %The "Drupal\\Core\\Entity\\Query\\QueryBase::hasAnyTag\(\)" method will require a new "string \.\.\. \$tags" argument in the next major version of its interface%
-
-# Symfony 7.3.
-%Since symfony/validator 7.3: Passing an array of options to configure the "[^"]+" constraint is deprecated, use named arguments instead.%
diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml
index 8bbffd2acb29cd3adae25f424f8c514af4177f2b..2a8b5add092ec15b5ac9fab68a24f1954eb28c0d 100644
--- a/core/config/schema/core.data_types.schema.yml
+++ b/core/config/schema/core.data_types.schema.yml
@@ -53,7 +53,8 @@ mapping:
   constraints:
     # By default, allow the explicitly listed mapping keys, and require their
     # presence unless `requiredKey: false` is specified.
-    ValidKeys: '<infer>'
+    ValidKeys:
+      allowedKeys: '<infer>'
 sequence:
   label: Sequence
   class: '\Drupal\Core\Config\Schema\Sequence'
@@ -191,13 +192,16 @@ _core_config_info:
       label: 'Default configuration hash'
       constraints:
         NotNull: []
-        Regex: '/^[a-zA-Z0-9\-_]+$/'
+        Regex:
+          pattern: '/^[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
+        Length:
+          exactly: 43
   constraints:
-    ValidKeys: ['default_config_hash']
+    ValidKeys:
+      allowedKeys: ['default_config_hash']
 
 config_object:
   type: mapping
@@ -373,7 +377,8 @@ config_dependencies_base:
         constraints:
           NotBlank: []
           ExtensionName: []
-          ExtensionExists: module
+          ExtensionExists:
+            type: module
     theme:
       # All dependency keys are optional: this might not depend on any themes.
       requiredKey: false
@@ -384,9 +389,11 @@ config_dependencies_base:
         constraints:
           NotBlank: []
           ExtensionName: []
-          ExtensionExists: theme
+          ExtensionExists:
+            type: theme
   constraints:
-    ValidKeys: '<infer>'
+    ValidKeys:
+      allowedKeys: '<infer>'
 
 config_dependencies:
   type: config_dependencies_base
@@ -398,7 +405,8 @@ config_dependencies:
       type: config_dependencies_base
       label: 'Enforced configuration dependencies'
   constraints:
-    ValidKeys: '<infer>'
+    ValidKeys:
+      allowedKeys: '<infer>'
 
 config_entity:
   type: mapping
@@ -453,7 +461,8 @@ block_settings:
       constraints:
         NotBlank: []
         ExtensionName: []
-        ExtensionExists: module
+        ExtensionExists:
+          type: module
     context_mapping:
       requiredKey: false
       type: sequence
@@ -547,7 +556,8 @@ field_config_base:
       type: string
       label: 'Bundle'
       constraints:
-        EntityBundleExists: '%parent.entity_type'
+        EntityBundleExists:
+          entityTypeId: '%parent.entity_type'
     label:
       type: required_label
       label: 'Label'
diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml
index 47f9674785f03ad9d1bb6ccc553c4fdf06d2fb7f..dc7865f6044cbfcc400033042120c43dca4186d8 100644
--- a/core/config/schema/core.entity.schema.yml
+++ b/core/config/schema/core.entity.schema.yml
@@ -72,7 +72,8 @@ core.entity_view_display.*.*.*:
       type: string
       label: 'Bundle'
       constraints:
-        EntityBundleExists: '%parent.targetEntityType'
+        EntityBundleExists:
+          entityTypeId: '%parent.targetEntityType'
     mode:
       type: string
       label: 'View or form mode machine name'
@@ -139,7 +140,8 @@ core.entity_form_display.*.*.*:
       type: string
       label: 'Bundle'
       constraints:
-        EntityBundleExists: '%parent.targetEntityType'
+        EntityBundleExists:
+          entityTypeId: '%parent.targetEntityType'
     mode:
       type: string
       label: 'View or form mode machine name'
diff --git a/core/lib/Drupal/Component/Plugin/Context/ContextDefinitionInterface.php b/core/lib/Drupal/Component/Plugin/Context/ContextDefinitionInterface.php
index c18a704081ea598d1aff4d9d869fa7c95cc5ef24..a2682aa003114a67fc9c7afee16906934b4ebc9c 100644
--- a/core/lib/Drupal/Component/Plugin/Context/ContextDefinitionInterface.php
+++ b/core/lib/Drupal/Component/Plugin/Context/ContextDefinitionInterface.php
@@ -154,12 +154,16 @@ public function setConstraints(array $constraints);
    *
    * @param string $constraint_name
    *   The name of the constraint to add, i.e. its plugin id.
+   * phpcs:disable Drupal.Commenting
+   * @todo Uncomment new method parameter signature before drupal:12.0.0.
+   * @see https://www.drupal.org/project/drupal/issues/XXXXXX
    * @param array|null $options
    *   The constraint options as required by the constraint plugin, or NULL.
+   * phpcs:enable
    *
    * @return $this
    */
-  public function addConstraint($constraint_name, $options = NULL);
+  public function addConstraint($constraint_name, /* ?array */$options = NULL);
 
   /**
    * Gets a validation constraint.
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
index 3b15335a205fe4543210053a53984c103190b97e..e084b0a400adabd7452f8c850e5a8293c0dcd7b6 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
@@ -200,7 +200,7 @@ public function getConstraints() {
     $id_key = $this->getKey('id');
     if ($id_key) {
       $constraints += [
-        'ImmutableProperties' => [$id_key],
+        'ImmutableProperties' => ['properties' => [$id_key]],
       ];
     }
     return $constraints;
diff --git a/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/ConfigExistsConstraint.php b/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/ConfigExistsConstraint.php
index 85d22f5511d210543d620d0d47b100b702699ef1..9db3a41f9abcadf209aa78798cf814f50dbdfa05 100644
--- a/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/ConfigExistsConstraint.php
+++ b/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/ConfigExistsConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Checks that the value is the name of an existing config object.
@@ -15,7 +15,7 @@
   id: 'ConfigExists',
   label: new TranslatableMarkup('Config exists', [], ['context' => 'Validation'])
 )]
-class ConfigExistsConstraint extends SymfonyConstraint {
+class ConfigExistsConstraint extends ConstraintBase {
 
   /**
    * The error message.
diff --git a/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/LangcodeRequiredIfTranslatableValuesConstraint.php b/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/LangcodeRequiredIfTranslatableValuesConstraint.php
index 2ce27a56b6e49a9b7aa61679a4c23ceed8a4ea15..7552d17c6bb44e6d7f1fd16d991b75bbc94077ba 100644
--- a/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/LangcodeRequiredIfTranslatableValuesConstraint.php
+++ b/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/LangcodeRequiredIfTranslatableValuesConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validation constraint for translatable configuration.
@@ -16,7 +16,7 @@
   label: new TranslatableMarkup('Translatable config has langcode', [], ['context' => 'Validation']),
   type: ['config_object']
 )]
-class LangcodeRequiredIfTranslatableValuesConstraint extends SymfonyConstraint {
+class LangcodeRequiredIfTranslatableValuesConstraint extends ConstraintBase {
 
   /**
    * The error message if this config object is missing a `langcode`.
diff --git a/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/RequiredConfigDependenciesConstraint.php b/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/RequiredConfigDependenciesConstraint.php
index c766cee33c648ab7ca20dbd931744cbf50658f09..acd5050f792d395ba5f78014916075464928c425 100644
--- a/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/RequiredConfigDependenciesConstraint.php
+++ b/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/RequiredConfigDependenciesConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Checks that config dependencies contain specific types of entities.
@@ -15,7 +15,7 @@
   id: 'RequiredConfigDependencies',
   label: new TranslatableMarkup('Required config dependency types', [], ['context' => 'Validation'])
 )]
-class RequiredConfigDependenciesConstraint extends SymfonyConstraint {
+class RequiredConfigDependenciesConstraint extends ConstraintBase {
 
   /**
    * The error message.
diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
index 4034dd1ee09eeebb00400e08d1b815c618cc4b39..51d8444a0fd520bb899e941d243afcb82a4a27d4 100644
--- a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
+++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
@@ -33,10 +33,12 @@
   ],
   constraints: [
     'ImmutableProperties' => [
-      'id',
-      'targetEntityType',
-      'bundle',
-      'mode',
+      'properties' => [
+        'id',
+        'targetEntityType',
+        'bundle',
+        'mode',
+      ],
     ],
   ],
   config_export: [
diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php b/core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php
index b84d5c05a970963351fc7c90a43f22bf8ed56e78..f21ac4d7a0f24fd35a5b754dc9dff1c186346ea4 100644
--- a/core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php
+++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php
@@ -34,8 +34,10 @@
   ],
   constraints: [
     'ImmutableProperties' => [
-      'id',
-      'targetEntityType',
+      'properties' => [
+        'id',
+        'targetEntityType',
+      ],
     ],
   ],
   config_export: [
diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
index 8ee4318a8df18fa16ff4e0df461108b1ab0bf22a..475dc9a251c7b7977da6025da1c078ebf5e27b93 100644
--- a/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
+++ b/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
@@ -32,10 +32,12 @@
   ],
   constraints: [
     'ImmutableProperties' => [
-      'id',
-      'targetEntityType',
-      'bundle',
-      'mode',
+      'properties' => [
+        'id',
+        'targetEntityType',
+        'bundle',
+        'mode',
+      ],
     ],
   ],
   config_export: [
diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php b/core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php
index e1427520e1ecf71ba7a61d585f0ce3c6bf63cb87..b4bc1bd6ebfce9cf3d51e3c5d90fb6fe4b7505ba 100644
--- a/core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php
+++ b/core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php
@@ -36,8 +36,10 @@
   ],
   constraints: [
     'ImmutableProperties' => [
-      'id',
-      'targetEntityType',
+      'properties' => [
+        'id',
+        'targetEntityType',
+      ],
     ],
   ],
   config_export: [
diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php
index 9eab50b9a2224c03cf78d0052e08a78e3c01c07c..713b78f7f6b13e3d2317eed27cb5ae6851e23765 100644
--- a/core/lib/Drupal/Core/Entity/EntityType.php
+++ b/core/lib/Drupal/Core/Entity/EntityType.php
@@ -907,7 +907,7 @@ public function setConstraints(array $constraints) {
   /**
    * {@inheritdoc}
    */
-  public function addConstraint($constraint_name, $options = NULL) {
+  public function addConstraint($constraint_name, /* ?array */$options = NULL) {
     $this->constraints[$constraint_name] = $options;
     return $this;
   }
diff --git a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php
index fb11b64c2dd88d96afbf7ab25fcdb1e46b254dc0..a49ea6a82efa4fc7648b100ee3ec7db5b9bd1b3e 100644
--- a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php
@@ -803,12 +803,16 @@ public function setConstraints(array $constraints);
    *
    * @param string $constraint_name
    *   The name of the constraint to add, i.e. its plugin id.
+   * phpcs:disable Drupal.Commenting
+   * @todo Uncomment new method parameter signature before drupal:12.0.0.
+   * @see https://www.drupal.org/project/drupal/issues/XXXXXX
    * @param array|null $options
    *   The constraint options as required by the constraint plugin, or NULL.
+   * phpcs:enable
    *
    * @return $this
    */
-  public function addConstraint($constraint_name, $options = NULL);
+  public function addConstraint($constraint_name, /* ?array */$options = NULL);
 
   /**
    * Gets the config dependency info for this entity, if any exists.
diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php
index 66b0f6871c5df62ccaca66424708a74b7e848cd0..52e54c44358be1b490eee229062423c91ccce38e 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php
@@ -23,7 +23,7 @@
  * type and bundle of the referenced entity can be created as following:
  * @code
  * $definition = \Drupal\Core\Entity\EntityDefinition::create($entity_type)
- *   ->addConstraint('Bundle', $bundle);
+ *   ->addConstraint('Bundle', ['bundle' => $bundle]);
  * \Drupal\Core\TypedData\DataReferenceDefinition::create('entity')
  *   ->setTargetDefinition($definition);
  * @endcode
diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/BundleConstraint.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/BundleConstraint.php
index ee1c82e30bfc1e5bed58bafe1cd673ea8f1695d4..2e58500901abb594d1502dd72e709d64280b6949 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/BundleConstraint.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/BundleConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Checks if a value is a valid entity type.
@@ -17,7 +17,7 @@
   label: new TranslatableMarkup('Bundle', [], ['context' => 'Validation']),
   type: ['entity', 'entity_reference']
 )]
-class BundleConstraint extends SymfonyConstraint {
+class BundleConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraint.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraint.php
index 8ec9d2fba6f0c9dfc960517612c6404e437d3eb2..7347863494fbadc74d168cde51aa4de6ad5af000 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraint.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityChangedConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validation constraint for the entity changed timestamp.
@@ -14,7 +14,7 @@
   label: new TranslatableMarkup('Entity changed', [], ['context' => 'Validation']),
   type: ['entity']
 )]
-class EntityChangedConstraint extends SymfonyConstraint {
+class EntityChangedConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityHasFieldConstraint.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityHasFieldConstraint.php
index 9d872ffdcb1f8c0c09954a020df456a572863412..367b041413c00b6a4d18d76c15764a81cd209649 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityHasFieldConstraint.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityHasFieldConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Checks if a value is an entity that has a specific field.
@@ -14,7 +14,7 @@
   label: new TranslatableMarkup('Entity has field', [], ['context' => 'Validation']),
   type: ['entity']
 )]
-class EntityHasFieldConstraint extends SymfonyConstraint {
+class EntityHasFieldConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityTypeConstraint.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityTypeConstraint.php
index 8cb4009a146ebf8c4c6d9cc2bbc8db02a8575c32..7435caba60810a339468467ec0c8d7d58880f6b9 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityTypeConstraint.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityTypeConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Checks if a value is a valid entity type.
@@ -14,7 +14,7 @@
   label: new TranslatableMarkup('Entity type', [], ['context' => 'Validation']),
   type: ['entity', 'entity_reference']
 )]
-class EntityTypeConstraint extends SymfonyConstraint {
+class EntityTypeConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityUntranslatableFieldsConstraint.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityUntranslatableFieldsConstraint.php
index f49012133c8bac7060a6a71a71d4113c85939e3a..0d4ee259590f11ca7294d6617e4f2576b0c24116 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityUntranslatableFieldsConstraint.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/EntityUntranslatableFieldsConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validation constraint for the entity changed timestamp.
@@ -14,7 +14,7 @@
   label: new TranslatableMarkup('Entity untranslatable fields', [], ['context' => 'Validation']),
   type: ['entity']
 )]
-class EntityUntranslatableFieldsConstraint extends SymfonyConstraint {
+class EntityUntranslatableFieldsConstraint extends ConstraintBase {
 
   /**
    * The message when updating a field but not the current revision.
diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ImmutablePropertiesConstraint.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ImmutablePropertiesConstraint.php
index 8de5b974abc8a887341a3d6c689a458ac216f924..3311a2510e2c18e98b35f00bd489b780563927b4 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ImmutablePropertiesConstraint.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ImmutablePropertiesConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Checks if config entity properties have been changed.
@@ -16,7 +16,7 @@
   label: new TranslatableMarkup('Properties are unchanged', [], ['context' => 'Validation']),
   type: ['entity']
 )]
-class ImmutablePropertiesConstraint extends SymfonyConstraint {
+class ImmutablePropertiesConstraint extends ConstraintBase {
 
   /**
    * The error message if an immutable property has been changed.
diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ReferenceAccessConstraint.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ReferenceAccessConstraint.php
index 90b924d90a370e44cb26c136c4bddf0c74dbeccf..a10d0d316513afdb681b48d85b42e22d6e87319b 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ReferenceAccessConstraint.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ReferenceAccessConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Entity Reference valid reference constraint.
@@ -15,7 +15,7 @@
   id: 'ReferenceAccess',
   label: new TranslatableMarkup('Entity Reference reference access', [], ['context' => 'Validation'])
 )]
-class ReferenceAccessConstraint extends SymfonyConstraint {
+class ReferenceAccessConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraint.php b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraint.php
index e5bc3de1a73f76af564bba09552f741612c39cd8..6dbb577f642e7e6e52a96d9aa3ba16677f0cc767 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraint.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/Validation/Constraint/ValidReferenceConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Entity Reference valid reference constraint.
@@ -15,7 +15,7 @@
   id: 'ValidReference',
   label: new TranslatableMarkup('Entity Reference valid reference', [], ['context' => 'Validation'])
 )]
-class ValidReferenceConstraint extends SymfonyConstraint {
+class ValidReferenceConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php b/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php
index 0bf4966dd9ffc2c3753df0001db8630bb2744891..3aaeabe88c277e1b2981b0c003b79abd1e36f53a 100644
--- a/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php
+++ b/core/lib/Drupal/Core/Entity/TypedData/EntityDataDefinition.php
@@ -117,21 +117,21 @@ public function getDataType() {
    * {@inheritdoc}
    */
   public function getEntityTypeId() {
-    return $this->definition['constraints']['EntityType'] ?? NULL;
+    return $this->definition['constraints']['EntityType']['type'] ?? NULL;
   }
 
   /**
    * {@inheritdoc}
    */
   public function setEntityTypeId($entity_type_id) {
-    return $this->addConstraint('EntityType', $entity_type_id);
+    return $this->addConstraint('EntityType', ['type' => $entity_type_id]);
   }
 
   /**
    * {@inheritdoc}
    */
   public function getBundles() {
-    $bundle = $this->definition['constraints']['Bundle'] ?? NULL;
+    $bundle = $this->definition['constraints']['Bundle']['bundle'] ?? NULL;
     return is_string($bundle) ? [$bundle] : $bundle;
   }
 
@@ -140,7 +140,7 @@ public function getBundles() {
    */
   public function setBundles(?array $bundles = NULL) {
     if (isset($bundles)) {
-      $this->addConstraint('Bundle', $bundles);
+      $this->addConstraint('Bundle', ['bundle' => $bundles]);
     }
     else {
       // Remove the constraint.
diff --git a/core/lib/Drupal/Core/Extension/Plugin/Validation/Constraint/ExtensionExistsConstraint.php b/core/lib/Drupal/Core/Extension/Plugin/Validation/Constraint/ExtensionExistsConstraint.php
index 5a555695311aa79571c39a16a64f3822500d7a6e..b2adcb6f3887e5750187252bd7c15fc6e1c7bfbb 100644
--- a/core/lib/Drupal/Core/Extension/Plugin/Validation/Constraint/ExtensionExistsConstraint.php
+++ b/core/lib/Drupal/Core/Extension/Plugin/Validation/Constraint/ExtensionExistsConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Checks that the value is the name of an installed extension.
@@ -15,7 +15,7 @@
   id: 'ExtensionExists',
   label: new TranslatableMarkup('Extension exists', [], ['context' => 'Validation'])
 )]
-class ExtensionExistsConstraint extends SymfonyConstraint {
+class ExtensionExistsConstraint extends ConstraintBase {
 
   /**
    * The error message for a non-existent module.
diff --git a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
index d8a96660c9661182471d07673632fd5100ac06f0..012e8d48049f84be9fc15b43cf24267038cb5ec4 100644
--- a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
+++ b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
@@ -305,7 +305,7 @@ public function isMultiple() {
    */
   public function setPropertyConstraints($name, array $constraints) {
     $item_constraints = $this->getItemDefinition()->getConstraints();
-    $item_constraints['ComplexData'][$name] = $constraints;
+    $item_constraints['ComplexData']['properties'][$name] = $constraints;
     $this->getItemDefinition()->setConstraints($item_constraints);
     return $this;
   }
@@ -343,7 +343,7 @@ public function setPropertyConstraints($name, array $constraints) {
    * @see \Drupal\Core\Field\BaseFieldDefinition::addConstraint()
    */
   public function addPropertyConstraints($name, array $constraints) {
-    $item_constraints = $this->getItemDefinition()->getConstraint('ComplexData') ?: [];
+    $item_constraints = $this->getItemDefinition()->getConstraint('ComplexData')['properties'] ?? [];
     if (isset($item_constraints[$name])) {
       // Add the new property constraints, overwriting as required.
       $item_constraints[$name] = $constraints + $item_constraints[$name];
@@ -351,7 +351,7 @@ public function addPropertyConstraints($name, array $constraints) {
     else {
       $item_constraints[$name] = $constraints;
     }
-    $this->getItemDefinition()->addConstraint('ComplexData', $item_constraints);
+    $this->getItemDefinition()->addConstraint('ComplexData', ['properties' => $item_constraints]);
     return $this;
   }
 
diff --git a/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php b/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php
index 0f28e265203bef6d9cb2796916332e2662135f9e..00f5e4909a5ebff7c8dcfdb5964b6694b154fd7a 100644
--- a/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php
+++ b/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php
@@ -30,11 +30,13 @@
   ],
   constraints: [
     'ImmutableProperties' => [
-      'id',
-      'entity_type',
-      'bundle',
-      'field_name',
-      'field_type',
+      'properties' => [
+        'id',
+        'entity_type',
+        'bundle',
+        'field_name',
+        'field_type',
+      ],
     ],
   ],
   config_export: [
diff --git a/core/lib/Drupal/Core/Field/FieldConfigBase.php b/core/lib/Drupal/Core/Field/FieldConfigBase.php
index 39405c37d437dae592076ecb5ce9a65ba96dd26b..09d796fb88d59cf711c428b7b9401a192c243599 100644
--- a/core/lib/Drupal/Core/Field/FieldConfigBase.php
+++ b/core/lib/Drupal/Core/Field/FieldConfigBase.php
@@ -557,7 +557,7 @@ public function getItemDefinition() {
         ->setSettings($this->getSettings());
 
       // Add any custom property constraints, overwriting as required.
-      $item_constraints = $this->itemDefinition->getConstraint('ComplexData') ?: [];
+      $item_constraints = $this->itemDefinition->getConstraint('ComplexData')['properties'] ?? [];
       foreach ($this->propertyConstraints as $name => $constraints) {
         if (isset($item_constraints[$name])) {
           $item_constraints[$name] = $constraints + $item_constraints[$name];
@@ -565,7 +565,7 @@ public function getItemDefinition() {
         else {
           $item_constraints[$name] = $constraints;
         }
-        $this->itemDefinition->addConstraint('ComplexData', $item_constraints);
+        $this->itemDefinition->addConstraint('ComplexData', ['properties' => $item_constraints]);
       }
     }
 
@@ -590,7 +590,7 @@ public function setConstraints(array $constraints) {
   /**
    * {@inheritdoc}
    */
-  public function addConstraint($constraint_name, $options = NULL) {
+  public function addConstraint($constraint_name, /* ?array */$options = NULL) {
     $this->constraints[$constraint_name] = $options;
     return $this;
   }
diff --git a/core/lib/Drupal/Core/Field/FieldConfigInterface.php b/core/lib/Drupal/Core/Field/FieldConfigInterface.php
index 7075c106dd4a5cbf65dd5b7212634be78350bdd6..a1fbb787c89932d1773f5241df01695d29e8d37f 100644
--- a/core/lib/Drupal/Core/Field/FieldConfigInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldConfigInterface.php
@@ -242,8 +242,12 @@ public function addPropertyConstraints($name, array $constraints);
    *
    * @param string $constraint_name
    *   The name of the constraint to add, i.e. its plugin id.
+   * phpcs:disable Drupal.Commenting
+   * @todo Uncomment new method parameter signature before drupal:12.0.0.
+   * @see https://www.drupal.org/project/drupal/issues/XXXXXX
    * @param array|null $options
    *   The constraint options as required by the constraint plugin, or NULL.
+   * phpcs:enable
    *
    * @return static
    *   The object itself for chaining.
@@ -252,7 +256,7 @@ public function addPropertyConstraints($name, array $constraints);
    * @see \Drupal\Core\Field\FieldConfigInterface::addPropertyConstraints()
    * @see hook_entity_bundle_field_info_alter()
    */
-  public function addConstraint($constraint_name, $options = NULL);
+  public function addConstraint($constraint_name, /* ?array */$options = NULL);
 
   /**
    * Sets the array of validation constraints for the FieldItemList.
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EmailItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EmailItem.php
index 33c8849f3f95e8a85de68db8173e318919b027c3..0c38aee7a4c4659c742b9275dd7c3a302bb6e32a 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EmailItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EmailItem.php
@@ -56,13 +56,15 @@ public function getConstraints() {
     $constraints = parent::getConstraints();
 
     $constraints[] = $constraint_manager->create('ComplexData', [
-      'value' => [
-        'Length' => [
-          'max' => Email::EMAIL_MAX_LENGTH,
-          'maxMessage' => $this->t('%name: the email address can not be longer than @max characters.', [
-            '%name' => $this->getFieldDefinition()->getLabel(),
-            '@max' => Email::EMAIL_MAX_LENGTH,
-          ]),
+      'properties' => [
+        'value' => [
+          'Length' => [
+            'max' => Email::EMAIL_MAX_LENGTH,
+            'maxMessage' => $this->t('%name: the email address can not be longer than @max characters.', [
+              '%name' => $this->getFieldDefinition()->getLabel(),
+              '@max' => Email::EMAIL_MAX_LENGTH,
+            ]),
+          ],
         ],
       ],
     ]);
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
index e614255f51869b6da1e682c4a0a08cbba427c28a..a5c1f0b1685d5a244ab758f66de291a0f3c6b597 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
@@ -105,7 +105,7 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
       // We can add a constraint for the target entity type. The list of
       // referenceable bundles is a field setting, so the corresponding
       // constraint is added dynamically in ::getConstraints().
-      ->addConstraint('EntityType', $settings['target_type']);
+      ->addConstraint('EntityType', ['type' => $settings['target_type']]);
 
     return $properties;
   }
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php
index a3125b2ea531c163d206fcf82d1412b4d64e1389..820c70118b17b05fe93d243c8d6c73a445d0e87e 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php
@@ -71,13 +71,15 @@ public function getConstraints() {
     if ($this->getSetting('unsigned')) {
       $constraint_manager = \Drupal::typedDataManager()->getValidationConstraintManager();
       $constraints[] = $constraint_manager->create('ComplexData', [
-        'value' => [
-          'Range' => [
-            'min' => 0,
-            'minMessage' => $this->t('%name: The integer must be larger or equal to %min.', [
-              '%name' => $this->getFieldDefinition()->getLabel(),
-              '%min' => 0,
-            ]),
+        'properties' => [
+          'value' => [
+            'Range' => [
+              'min' => 0,
+              'minMessage' => $this->t('%name: The integer must be larger or equal to %min.', [
+                '%name' => $this->getFieldDefinition()->getLabel(),
+                '%min' => 0,
+              ]),
+            ],
           ],
         ],
       ]);
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php
index 99357d4574d12184343b567f3f05b82bfb945c22..e7f4a5a2aec712bb0bc76a80a6bd6bff7b4da2d8 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/LanguageItem.php
@@ -25,8 +25,10 @@
   no_ui: TRUE,
   constraints: [
     "ComplexData" => [
-      "value" => [
-        "Length" => ["max" => 12],
+      "properties" => [
+        "value" => [
+          "Length" => ["max" => 12],
+        ],
       ],
     ],
   ]
@@ -112,7 +114,7 @@ public function onChange($property_name, $notify = TRUE) {
    */
   public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
     // Defer to the callback in the item definition as it can be overridden.
-    $constraint = $field_definition->getItemDefinition()->getConstraint('ComplexData');
+    $constraint = $field_definition->getItemDefinition()->getConstraint('ComplexData')['properties'] ?? [];
     if (isset($constraint['value']['AllowedValues']['callback'])) {
       $languages = call_user_func($constraint['value']['AllowedValues']['callback']);
     }
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php
index fb1bea28c5cd8828034c01072d9f5e83698285cb..c26eceef2f1169da3cf64f211c750e26e545e54d 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/NumericItemBase.php
@@ -82,10 +82,12 @@ public function getConstraints() {
     if (isset($settings['min']) && $settings['min'] !== '') {
       $min = $settings['min'];
       $constraints[] = $constraint_manager->create('ComplexData', [
-        'value' => [
-          'Range' => [
-            'min' => $min,
-            'minMessage' => $this->t('%name: the value may be no less than %min.', ['%name' => $label, '%min' => $min]),
+        'properties' => [
+          'value' => [
+            'Range' => [
+              'min' => $min,
+              'minMessage' => $this->t('%name: the value may be no less than %min.', ['%name' => $label, '%min' => $min]),
+            ],
           ],
         ],
       ]);
@@ -94,13 +96,15 @@ public function getConstraints() {
     if (isset($settings['max']) && $settings['max'] !== '') {
       $max = $settings['max'];
       $constraints[] = $constraint_manager->create('ComplexData', [
-        'value' => [
-          'Range' => [
-            'max' => $max,
-            'maxMessage' => $this->t('%name: the value may be no greater than %max.', [
-              '%name' => $label,
-              '%max' => $max,
-            ]),
+        'properties' => [
+          'value' => [
+            'Range' => [
+              'max' => $max,
+              'maxMessage' => $this->t('%name: the value may be no greater than %max.', [
+                '%name' => $label,
+                '%max' => $max,
+              ]),
+            ],
           ],
         ],
       ]);
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItem.php
index cbe14fab73785de0fb38fbc505e5683ef2a4f7cd..54d832827e37f0d29be19f0852474e983b3ac3e6 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/StringItem.php
@@ -68,8 +68,10 @@ public function getConstraints() {
         ]);
       }
       $constraints[] = $constraint_manager->create('ComplexData', [
-        'value' => [
-          'Length' => $options,
+        'properties' => [
+          'value' => [
+            'Length' => $options,
+          ],
         ],
       ]);
     }
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php
index 79d7353894bd3f12f45c5edfc1510d03ed0f0fe8..d412df89b622a88ea1cb8238a806a13363cd1b80 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/TimestampItem.php
@@ -25,10 +25,12 @@
   default_formatter: "timestamp",
   constraints: [
     "ComplexData" => [
-      "value" => [
-        "Range" => [
-          "min" => "-2147483648",
-          "max" => "2147483648",
+      'properties' => [
+        "value" => [
+          "Range" => [
+            "min" => "-2147483648",
+            "max" => "2147483648",
+          ],
         ],
       ],
     ],
diff --git a/core/lib/Drupal/Core/Menu/Plugin/Validation/Constraint/MenuLinkDepthConstraint.php b/core/lib/Drupal/Core/Menu/Plugin/Validation/Constraint/MenuLinkDepthConstraint.php
index b038960ed8086458d01acc79e62e970717d1ded7..1ef9deac339d3381045c1cc3f3ddb38e206c639a 100644
--- a/core/lib/Drupal/Core/Menu/Plugin/Validation/Constraint/MenuLinkDepthConstraint.php
+++ b/core/lib/Drupal/Core/Menu/Plugin/Validation/Constraint/MenuLinkDepthConstraint.php
@@ -7,6 +7,7 @@
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
 use Drupal\Core\Validation\Plugin\Validation\Constraint\RangeConstraint;
+use Symfony\Component\Validator\Attribute\HasNamedArguments;
 
 /**
  * Validates the link depth of a menu tree.
@@ -19,10 +20,14 @@
 class MenuLinkDepthConstraint extends RangeConstraint {
 
   /**
-   * The initial level of menu items that are being exposed (zero-based).
-   *
-   * @var string|int
+   * @param string|int $baseLevel
+   *   The initial level of menu items that are being exposed (zero-based).
+   * @param array<string, mixed> $args
+   *   Additional arguments to pass to parent constructor.
    */
-  public string|int $baseLevel = 0;
+  #[HasNamedArguments]
+  public function __construct(public readonly string|int $baseLevel = 0, ...$args) {
+    parent::__construct(...$args);
+  }
 
 }
diff --git a/core/lib/Drupal/Core/Path/Plugin/Validation/Constraint/UniquePathAliasConstraint.php b/core/lib/Drupal/Core/Path/Plugin/Validation/Constraint/UniquePathAliasConstraint.php
index b97e12eeb81a55f1d3c001531bf39f9e26c7b8b0..0d7d6fc5e122c2d2bd1a0e0b5349f45fcd55079a 100644
--- a/core/lib/Drupal/Core/Path/Plugin/Validation/Constraint/UniquePathAliasConstraint.php
+++ b/core/lib/Drupal/Core/Path/Plugin/Validation/Constraint/UniquePathAliasConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validation constraint for unique path alias values.
@@ -13,7 +13,7 @@
   id: 'UniquePathAlias',
   label: new TranslatableMarkup('Unique path alias.', [], ['context' => 'Validation'])
 )]
-class UniquePathAliasConstraint extends SymfonyConstraint {
+class UniquePathAliasConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/lib/Drupal/Core/Path/Plugin/Validation/Constraint/ValidPathConstraint.php b/core/lib/Drupal/Core/Path/Plugin/Validation/Constraint/ValidPathConstraint.php
index be69501609d19fc1a87b5ebf0944746bcafb80d4..f6854f65eaccd8ec4f55daf221706227255e206c 100644
--- a/core/lib/Drupal/Core/Path/Plugin/Validation/Constraint/ValidPathConstraint.php
+++ b/core/lib/Drupal/Core/Path/Plugin/Validation/Constraint/ValidPathConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validation constraint for valid system paths.
@@ -13,7 +13,7 @@
   id: 'ValidPath',
   label: new TranslatableMarkup('Valid path.', [], ['context' => 'Validation'])
 )]
-class ValidPathConstraint extends SymfonyConstraint {
+class ValidPathConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php
index 30859de203a5aabc7c91ab28f2552bc5ec425ed9..99fd9c0f7ec7a1261df3c60253cea172bdd9641a 100644
--- a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php
+++ b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php
@@ -236,7 +236,7 @@ public function setConstraints(array $constraints) {
   /**
    * {@inheritdoc}
    */
-  public function addConstraint($constraint_name, $options = NULL) {
+  public function addConstraint($constraint_name, /* ?array */$options = NULL) {
     $this->constraints[$constraint_name] = $options;
     return $this;
   }
diff --git a/core/lib/Drupal/Core/Plugin/Plugin/Validation/Constraint/PluginExistsConstraint.php b/core/lib/Drupal/Core/Plugin/Plugin/Validation/Constraint/PluginExistsConstraint.php
index 83d38ee2bbae48407fbfd74f7d42fce94241dc92..96eafc9067fd8278ffbf201065daa1135161e46f 100644
--- a/core/lib/Drupal/Core/Plugin/Plugin/Validation/Constraint/PluginExistsConstraint.php
+++ b/core/lib/Drupal/Core/Plugin/Plugin/Validation/Constraint/PluginExistsConstraint.php
@@ -9,7 +9,7 @@
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 use Symfony\Component\Validator\Exception\MissingOptionsException;
 
 /**
@@ -19,7 +19,7 @@
   id: 'PluginExists',
   label: new TranslatableMarkup('Plugin exists', [], ['context' => 'Validation'])
 )]
-class PluginExistsConstraint extends SymfonyConstraint implements ContainerFactoryPluginInterface {
+class PluginExistsConstraint extends ConstraintBase implements ContainerFactoryPluginInterface {
 
   /**
    * The error message if a plugin does not exist.
@@ -70,7 +70,13 @@ class PluginExistsConstraint extends SymfonyConstraint implements ContainerFacto
    *   Domain-specific data attached to a constraint.
    */
   public function __construct(public readonly PluginManagerInterface $pluginManager, mixed $options = NULL, ?array $groups = NULL, mixed $payload = NULL) {
-    parent::__construct($options, $groups, $payload);
+    if ($groups) {
+      $options['groups'] = $groups;
+    }
+    if ($payload) {
+      $options['payload'] = $payload;
+    }
+    parent::__construct(...$options);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/TypedData/DataDefinition.php b/core/lib/Drupal/Core/TypedData/DataDefinition.php
index 66145088839ecd7eb46c4acf0e9f9c5ab70958d6..d4c7e67200ae7da3910f6e1552db38a214bf8c07 100644
--- a/core/lib/Drupal/Core/TypedData/DataDefinition.php
+++ b/core/lib/Drupal/Core/TypedData/DataDefinition.php
@@ -303,7 +303,7 @@ public function setConstraints(array $constraints) {
   /**
    * {@inheritdoc}
    */
-  public function addConstraint($constraint_name, $options = NULL) {
+  public function addConstraint($constraint_name, /* ?array */$options = NULL) {
     $this->definition['constraints'][$constraint_name] = $options;
     return $this;
   }
diff --git a/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php b/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php
index 2ecada0e5d93013c6e22b19137ba0065908f4999..930f3ce68e3d60c527c337a6695b46ec15375211 100644
--- a/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php
+++ b/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php
@@ -213,13 +213,17 @@ public function getConstraint($constraint_name);
    *
    * @param string $constraint_name
    *   The name of the constraint to add, i.e. its plugin id.
+   * phpcs:disable Drupal.Commenting
+   * @todo Uncomment new method parameter signature before drupal:12.0.0.
+   * @see https://www.drupal.org/project/drupal/issues/XXXXXX
    * @param array|null $options
    *   The constraint options as required by the constraint plugin, or NULL.
+   * phpcs:enable
    *
    * @return static
    *   The object itself for chaining.
    */
-  public function addConstraint($constraint_name, $options = NULL);
+  public function addConstraint($constraint_name, /* ?array */$options = NULL);
 
   /**
    * Determines whether the data value is internal.
diff --git a/core/lib/Drupal/Core/Validation/ConstraintFactory.php b/core/lib/Drupal/Core/Validation/ConstraintFactory.php
index 3196dae1cb0be3e0d23ed8c9739589634e1bbf76..14874ecb09cc823efa33ff7d11b96e7af4c9b7d6 100644
--- a/core/lib/Drupal/Core/Validation/ConstraintFactory.php
+++ b/core/lib/Drupal/Core/Validation/ConstraintFactory.php
@@ -3,6 +3,7 @@
 namespace Drupal\Core\Validation;
 
 use Drupal\Core\Plugin\Factory\ContainerFactory;
+use Symfony\Component\Validator\Attribute\HasNamedArguments;
 use Symfony\Component\Validator\Constraint;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 
@@ -18,6 +19,9 @@ class ConstraintFactory extends ContainerFactory {
    * {@inheritdoc}
    */
   public function createInstance($plugin_id, array $configuration = []) {
+    $options_not_passed_as_array = !empty($configuration['_options_not_passed_as_array']);
+    unset($configuration['_options_not_passed_as_array']);
+
     $plugin_definition = $this->discovery->getDefinition($plugin_id);
     $plugin_class = static::getPluginClass($plugin_id, $plugin_definition, $this->interface);
 
@@ -28,7 +32,21 @@ public function createInstance($plugin_id, array $configuration = []) {
 
     // If the plugin is a Symfony Constraint, use the correct constructor.
     if (is_subclass_of($plugin_class, Constraint::class)) {
-      return new $plugin_class($configuration);
+      $configuration_is_list = !empty($configuration) && array_is_list($configuration);
+      if ($options_not_passed_as_array || $configuration_is_list) {
+        return new $plugin_class($configuration);
+      }
+
+      $reflection_method = new \ReflectionMethod($plugin_class, '__construct');
+      if (!$configuration) {
+        if ($reflection_method->getNumberOfRequiredParameters() > 0) {
+          return new $plugin_class($configuration);
+        }
+        return new $plugin_class();
+      }
+
+      $has_named_arguments = (bool) $reflection_method->getAttributes(HasNamedArguments::class);
+      return $has_named_arguments ? new $plugin_class(...$configuration) : new $plugin_class($configuration);
     }
 
     // Otherwise, create the plugin as normal.
diff --git a/core/lib/Drupal/Core/Validation/ConstraintManager.php b/core/lib/Drupal/Core/Validation/ConstraintManager.php
index 00f3c862af459204b9bd7d0b0a4f938dfcea80b0..703f9dc292fa073ecfd2525f226c096c368aa771 100644
--- a/core/lib/Drupal/Core/Validation/ConstraintManager.php
+++ b/core/lib/Drupal/Core/Validation/ConstraintManager.php
@@ -70,7 +70,7 @@ protected function getDiscovery() {
    *
    * @param string $name
    *   The name or plugin id of the constraint.
-   * @param mixed $options
+   * @param array<string, mixed>|null $options
    *   The options to pass to the constraint class. Required and supported
    *   options depend on the constraint class.
    *
@@ -79,10 +79,14 @@ protected function getDiscovery() {
    */
   public function create($name, $options) {
     if (!is_array($options)) {
+      if ($options !== NULL) {
+        @trigger_error(sprintf('Passing any non-associative-array options to configure constraint plugin "%s" is deprecated in drupal:11.3.0 and will not be supported in drupal:12.0.0. Use named arguments instead. See https://www.drupal.org/node/3522497', $name), E_USER_DEPRECATED);
+      }
       // Plugins need an array as configuration, so make sure we have one.
       // The constraint classes support passing the options as part of the
       // 'value' key also.
-      $options = isset($options) ? ['value' => $options] : [];
+      // @phpstan-ignore isset.variable
+      $options = isset($options) ? ['value' => $options, '_options_not_passed_as_array' => TRUE] : [];
     }
     return $this->createInstance($name, $options);
   }
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraint.php
index 18acb7abd7bc6fa5169652bf3e6daa59952e5179..871b4fb8a68f5beafa0e4d36f6f4e6322b83b603 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AllowedValuesConstraint.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
+use Symfony\Component\Validator\Attribute\HasNamedArguments;
 use Symfony\Component\Validator\Constraints\Choice;
 
 /**
@@ -20,6 +21,7 @@ class AllowedValuesConstraint extends Choice {
   /**
    * {@inheritdoc}
    */
+  #[HasNamedArguments]
   public function __construct(...$args) {
     $this->strict = TRUE;
     $this->minMessage = 'You must select at least %limit choice.|You must select at least %limit choices.';
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AtLeastOneOfConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AtLeastOneOfConstraint.php
index de99cd9985aeb76d0fd26c748a5e0c779b6336b7..ab1d342c19d64964002caac76275a3b97bf654e8 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AtLeastOneOfConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AtLeastOneOfConstraint.php
@@ -6,7 +6,6 @@
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
 use Symfony\Component\Validator\Constraints\AtLeastOneOf;
 
 /**
@@ -34,7 +33,7 @@ public static function create(ContainerInterface $container, array $configuratio
       }
     }
 
-    return new static($constraint_instances, [SymfonyConstraint::DEFAULT_GROUP]);
+    return new static($constraint_instances, [static::DEFAULT_GROUP]);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ClassResolverConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ClassResolverConstraint.php
index 677de9e73974bc0ac8d7b44782946079918840b8..b072e1e7ae49c12eede00c6750b4a4f0466116b4 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ClassResolverConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ClassResolverConstraint.php
@@ -6,7 +6,6 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
 
 /**
  * Checks if a method on a service or instantiated object returns true.
@@ -26,7 +25,7 @@
   label: new TranslatableMarkup('Call a method on a service', [], ['context' => 'Validation']),
   type: FALSE,
 )]
-class ClassResolverConstraint extends SymfonyConstraint {
+class ClassResolverConstraint extends ConstraintBase {
 
   /**
    * The error message if validation fails.
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ComplexDataConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ComplexDataConstraint.php
index e009122ff1397d1affc50ea4f10a1ef320f289de..ec358972b2b0ec62476ebc543968e5a4e64d4782 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ComplexDataConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ComplexDataConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Symfony\Component\Validator\Attribute\HasNamedArguments;
 
 /**
  * Complex data constraint.
@@ -15,7 +15,7 @@
   id: 'ComplexData',
   label: new TranslatableMarkup('Complex data', [], ['context' => 'Validation'])
 )]
-class ComplexDataConstraint extends SymfonyConstraint {
+class ComplexDataConstraint extends ConstraintBase {
 
   /**
    * An array of constraints for contained properties, keyed by property name.
@@ -27,12 +27,16 @@ class ComplexDataConstraint extends SymfonyConstraint {
   /**
    * {@inheritdoc}
    */
-  public function __construct($options = NULL) {
-    // Allow skipping the 'properties' key in the options.
-    if (is_array($options) && !array_key_exists('properties', $options)) {
-      $options = ['properties' => $options];
+  #[HasNamedArguments]
+  public function __construct(...$args) {
+    if (!empty($args) && array_is_list($args)) {
+      // Allow skipping the 'properties' key in the options.
+      if (!array_key_exists('properties', $args[0])) {
+        $args[0] = ['properties' => $args[0]];
+      }
     }
-    parent::__construct($options);
+
+    parent::__construct(...$args);
     $constraint_manager = \Drupal::service('validation.constraint');
 
     // Instantiate constraint objects for array definitions.
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ConstraintBase.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ConstraintBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..b0f030e00de44ec54f619eba61e18ed0c0422554
--- /dev/null
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ConstraintBase.php
@@ -0,0 +1,29 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
+
+use Symfony\Component\Validator\Attribute\HasNamedArguments;
+use Symfony\Component\Validator\Constraint;
+
+/**
+ * Base class for constraint plugins.
+ *
+ * This provides generic support for named option parameters passed to the
+ * class constructor.
+ */
+abstract class ConstraintBase extends Constraint {
+
+  #[HasNamedArguments]
+  public function __construct(...$args) {
+    if (!empty($args) && array_is_list($args)) {
+      @trigger_error(sprintf('Passing an array of options to configure the "%s" constraint is deprecated in drupal:11.3.0 and will not be supported in drupal:12.0.0. Use named arguments instead. See https://www.drupal.org/node/3522497', get_class($this)), E_USER_DEPRECATED);
+      parent::__construct(...$args);
+      return;
+    }
+
+    parent::__construct($args);
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/CountConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/CountConstraint.php
index 9cde560037e532756636920d588dc3202dd7aeec..7c95d25d8f46127549b5d211bc05519f22e727dc 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/CountConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/CountConstraint.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
+use Symfony\Component\Validator\Attribute\HasNamedArguments;
 use Symfony\Component\Validator\Constraints\Count;
 
 /**
@@ -21,6 +22,7 @@ class CountConstraint extends Count {
   /**
    * {@inheritdoc}
    */
+  #[HasNamedArguments]
   public function __construct(...$args) {
     $this->minMessage = 'This collection should contain %limit element or more.|This collection should contain %limit elements or more.';
     $this->maxMessage = 'This collection should contain %limit element or less.|This collection should contain %limit elements or less.';
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/CountryCodeConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/CountryCodeConstraint.php
index 715607e3b668ac0796eced561b96b08080af795d..fb81ecabfda2922aeae3ac0abbc2fd9c741a5881 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/CountryCodeConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/CountryCodeConstraint.php
@@ -26,7 +26,7 @@ class CountryCodeConstraint implements ContainerFactoryPluginInterface {
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): Choice {
     $countries = $container->get(CountryManagerInterface::class)->getList();
     $configuration['choices'] = array_keys($countries);
-    return new Choice($configuration);
+    return new Choice(...$configuration);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EmailConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EmailConstraint.php
index fe0adf3720edf40c2a14da007e6a2eb992986906..a3bdef9ee8e1fd9ffe05beb2807051a00ea4a69f 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EmailConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EmailConstraint.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
+use Symfony\Component\Validator\Attribute\HasNamedArguments;
 use Symfony\Component\Validator\Constraints\Email;
 use Symfony\Component\Validator\Constraints\EmailValidator;
 
@@ -21,6 +22,7 @@ class EmailConstraint extends Email {
   /**
    * {@inheritdoc}
    */
+  #[HasNamedArguments]
   public function __construct(...$args) {
     $this->mode = static::VALIDATION_MODE_STRICT;
     parent::__construct(...$args);
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityBundleExistsConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityBundleExistsConstraint.php
index 61c2b443620a373a8ef97ea658fdcbc3d9730bc2..d8d739416b98db9a8a400b4e9baba38b1cd81208 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityBundleExistsConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/EntityBundleExistsConstraint.php
@@ -6,7 +6,6 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
 
 /**
  * Checks if a bundle exists on a certain content entity type.
@@ -19,7 +18,7 @@
   label: new TranslatableMarkup('Entity bundle exists', [], ['context' => 'Validation']),
   type: 'entity'
 )]
-class EntityBundleExistsConstraint extends SymfonyConstraint {
+class EntityBundleExistsConstraint extends ConstraintBase {
 
   /**
    * The error message if validation fails.
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/FullyValidatableConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/FullyValidatableConstraint.php
index 4bd10c54f220fa3fd60f57c4525ecb285064b434..74021245ad7950fc6dedd5e1d6700c10a78e1084 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/FullyValidatableConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/FullyValidatableConstraint.php
@@ -6,7 +6,6 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
 
 /**
  * Constraint for fully validatable config schema type.
@@ -15,4 +14,4 @@
   id: 'FullyValidatable',
   label: new TranslatableMarkup('Whether this config schema type is fully validatable', [], ['context' => 'Validation'])
 )]
-final class FullyValidatableConstraint extends SymfonyConstraint {}
+final class FullyValidatableConstraint extends ConstraintBase {}
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/LengthConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/LengthConstraint.php
index 021603c7e8269f3ce74ac3460a34bd02c7d749a7..078db9474c256d2b193d27434b671e3259400772 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/LengthConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/LengthConstraint.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
+use Symfony\Component\Validator\Attribute\HasNamedArguments;
 use Symfony\Component\Validator\Constraints\Length;
 
 /**
@@ -23,6 +24,7 @@ class LengthConstraint extends Length {
   /**
    * {@inheritdoc}
    */
+  #[HasNamedArguments]
   public function __construct(...$args) {
     $this->maxMessage = 'This value is too long. It should have %limit character or less.|This value is too long. It should have %limit characters or less.';
     $this->minMessage = 'This value is too short. It should have %limit character or more.|This value is too short. It should have %limit characters or more.';
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraint.php
index acdf03483c045c26d080d3aec94d1189a833a4fc..f8b6b12789fe193ab672b279c39d37cc9282e7de 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraint.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
 
 /**
  * Supports validating all primitive types.
@@ -13,7 +12,7 @@
   id: 'PrimitiveType',
   label: new TranslatableMarkup('Primitive type', [], ['context' => 'Validation'])
 )]
-class PrimitiveTypeConstraint extends SymfonyConstraint {
+class PrimitiveTypeConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/RangeConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/RangeConstraint.php
index 8a18df076c580bf20eee063d5a62586c32cef4f8..2f6dacbaf9dcbfc064c33f3ebfb28863a10f401b 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/RangeConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/RangeConstraint.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
+use Symfony\Component\Validator\Attribute\HasNamedArguments;
 use Symfony\Component\Validator\Constraints\Range;
 
 /**
@@ -23,6 +24,7 @@ class RangeConstraint extends Range {
   /**
    * {@inheritdoc}
    */
+  #[HasNamedArguments]
   public function __construct(...$args) {
     $this->notInRangeMessage = 'This value should be between %min and %max.';
     $this->minMessage = 'This value should be %limit or more.';
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldConstraint.php
index db9f1dc1ec31b659b2c020122f31491dd01b0b60..f496dd1ac3871034964f3b6cafe73efdff7cd7a3 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldConstraint.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
 
 /**
  * Checks if an entity field has a unique value.
@@ -13,7 +12,7 @@
   id: 'UniqueField',
   label: new TranslatableMarkup('Unique field constraint', [], ['context' => 'Validation'])
 )]
-class UniqueFieldConstraint extends SymfonyConstraint {
+class UniqueFieldConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UriHostConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UriHostConstraint.php
index 81386205d0e118a97fbdf1b71a257548db5860d8..327a7537db3ad0aff75ddec68f87f58d234b07b5 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UriHostConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UriHostConstraint.php
@@ -6,7 +6,6 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
 
 /**
  * Checks if a string conforms to the RFC 3986 host component.
@@ -15,7 +14,7 @@
   id: 'UriHost',
   label: new TranslatableMarkup('URI host', [], ['context' => 'Validation']),
 )]
-class UriHostConstraint extends SymfonyConstraint {
+class UriHostConstraint extends ConstraintBase {
 
   /**
    * The error message if validation fails.
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ValidKeysConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ValidKeysConstraint.php
index 5236d9afe41a6b2a6c69e0c08c3c06716aee6752..c09bf54f02048d4440b2c388fc0abe5972d3e5d6 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ValidKeysConstraint.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ValidKeysConstraint.php
@@ -7,7 +7,6 @@
 use Drupal\Core\Config\Schema\Mapping;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
 use Symfony\Component\Validator\Context\ExecutionContextInterface;
 use Symfony\Component\Validator\Exception\InvalidArgumentException;
 
@@ -19,7 +18,7 @@
   label: new TranslatableMarkup('Valid mapping keys', [], ['context' => 'Validation']),
   type: ['mapping']
 )]
-class ValidKeysConstraint extends SymfonyConstraint {
+class ValidKeysConstraint extends ConstraintBase {
 
   /**
    * The error message if a key is invalid.
diff --git a/core/modules/block/config/schema/block.schema.yml b/core/modules/block/config/schema/block.schema.yml
index 9c28c0b3723212c972f602318cb618f2928db84b..391e2091fbcc84354b113e1759e13ce7bbb56ea2 100644
--- a/core/modules/block/config/schema/block.schema.yml
+++ b/core/modules/block/config/schema/block.schema.yml
@@ -22,13 +22,15 @@ block.block.*:
       constraints:
         NotBlank: []
         ExtensionName: []
-        ExtensionExists: theme
+        ExtensionExists:
+          type: theme
     region:
       type: string
       label: 'Region'
       constraints:
         NotBlank: []
-        Callback: ['\Drupal\block\Entity\Block', validateRegion]
+        Callback:
+          callback: ['\Drupal\block\Entity\Block', validateRegion]
     weight:
       type: weight
       label: 'Weight'
diff --git a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/CKEditor5ElementConstraint.php b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/CKEditor5ElementConstraint.php
index f303b5fc97b7287e60bad45a83123088a6d7edea..1b569c44ad7800d748f8b2ff1722561eb2feeea5 100644
--- a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/CKEditor5ElementConstraint.php
+++ b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/CKEditor5ElementConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * CKEditor 5 element.
@@ -15,7 +15,7 @@
   id: 'CKEditor5Element',
   label: new TranslatableMarkup('CKEditor 5 element', [], ['context' => 'Validation'])
 )]
-class CKEditor5ElementConstraint extends SymfonyConstraint {
+class CKEditor5ElementConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/CKEditor5MediaAndFilterSettingsInSyncConstraint.php b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/CKEditor5MediaAndFilterSettingsInSyncConstraint.php
index b17747c3b7ce8092b236587baf45dae222b412d7..7ea89976f70120e4bcf476f080fb3324bbfd5a96 100644
--- a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/CKEditor5MediaAndFilterSettingsInSyncConstraint.php
+++ b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/CKEditor5MediaAndFilterSettingsInSyncConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Ensure CKEditor 5 media plugin's and media filter's settings are in sync.
@@ -17,7 +17,7 @@
   id: 'CKEditor5MediaAndFilterSettingsInSync',
   label: new TranslatableMarkup('CKEditor 5 Media plugin in sync with filter settings', [], ['context' => 'Validation'])
 )]
-class CKEditor5MediaAndFilterSettingsInSyncConstraint extends SymfonyConstraint {
+class CKEditor5MediaAndFilterSettingsInSyncConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/EnabledConfigurablePluginsConstraint.php b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/EnabledConfigurablePluginsConstraint.php
index 3d646ed389d42c9be54edfbbe6cd479ee3a73bd6..c3e77e59ec9362540423659267d04a71be2833e0 100644
--- a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/EnabledConfigurablePluginsConstraint.php
+++ b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/EnabledConfigurablePluginsConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * The CKEditor 5 plugin settings.
@@ -17,7 +17,7 @@
   id: 'CKEditor5EnabledConfigurablePlugins',
   label: new TranslatableMarkup('CKEditor 5 enabled configurable plugins', [], ['context' => 'Validation'])
 )]
-class EnabledConfigurablePluginsConstraint extends SymfonyConstraint {
+class EnabledConfigurablePluginsConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/FundamentalCompatibilityConstraint.php b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/FundamentalCompatibilityConstraint.php
index 866bb6c00ba5459bf0eb9a9d11bddc33c5fb7ab7..fe0c2493c98e294f2ce3fba948a4e37a443e4ce0 100644
--- a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/FundamentalCompatibilityConstraint.php
+++ b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/FundamentalCompatibilityConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * The fundamental compatibility constraint.
@@ -17,7 +17,7 @@
   id: 'CKEditor5FundamentalCompatibility',
   label: new TranslatableMarkup('CKEditor 5 fundamental text format compatibility', [], ['context' => 'Validation'])
 )]
-class FundamentalCompatibilityConstraint extends SymfonyConstraint {
+class FundamentalCompatibilityConstraint extends ConstraintBase {
 
   /**
    * The violation message when no markup filters are enabled.
diff --git a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/SourceEditingPreventSelfXssConstraint.php b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/SourceEditingPreventSelfXssConstraint.php
index 96677c690966b450e9e02684a28c76f41db7b5eb..8958234b46a35e2c770c1abea0882ab141d439bb 100644
--- a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/SourceEditingPreventSelfXssConstraint.php
+++ b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/SourceEditingPreventSelfXssConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * For disallowing Source Editing configuration that allows self-XSS.
@@ -17,7 +17,7 @@
   id: 'SourceEditingPreventSelfXssConstraint',
   label: new TranslatableMarkup('Source Editing should never allow self-XSS.', [], ['context' => 'Validation'])
 )]
-class SourceEditingPreventSelfXssConstraint extends SymfonyConstraint {
+class SourceEditingPreventSelfXssConstraint extends ConstraintBase {
 
   /**
    * When Source Editing is configured to allow self-XSS.
diff --git a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/SourceEditingRedundantTagsConstraint.php b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/SourceEditingRedundantTagsConstraint.php
index 703f31e462ae9440b4aa8a54f738a1bc14c50a2c..927c2112463c0ee0a1eb536b59e3bf9367d6437b 100644
--- a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/SourceEditingRedundantTagsConstraint.php
+++ b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/SourceEditingRedundantTagsConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * For disallowing Source Editing elements already supported by a plugin.
@@ -17,7 +17,7 @@
   id: 'SourceEditingRedundantTags',
   label: new TranslatableMarkup('Source editing should only use otherwise unavailable tags and attributes', [], ['context' => 'Validation'])
 )]
-class SourceEditingRedundantTagsConstraint extends SymfonyConstraint {
+class SourceEditingRedundantTagsConstraint extends ConstraintBase {
 
   /**
    * When a Source Editing element is added that an enabled plugin supports.
diff --git a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/StyleSensibleElementConstraint.php b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/StyleSensibleElementConstraint.php
index 2161b827f072f7c1b9bcff76ac9a7ba1b9b287b0..212c4755ea85f049161c1e1114e4ff49f3e7ba6e 100644
--- a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/StyleSensibleElementConstraint.php
+++ b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/StyleSensibleElementConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Styles can only be specified for HTML5 tags and extra classes.
@@ -17,7 +17,7 @@
   id: 'StyleSensibleElement',
   label: new TranslatableMarkup('Styles can only be specified for already supported tags.', [], ['context' => 'Validation'])
 )]
-class StyleSensibleElementConstraint extends SymfonyConstraint {
+class StyleSensibleElementConstraint extends ConstraintBase {
 
   /**
    * When a style is defined for a non-HTML5 tag.
diff --git a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/ToolbarItemConditionsMetConstraint.php b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/ToolbarItemConditionsMetConstraint.php
index 694595d06db2ef894e94b0aacadd6e887b94ed54..8b43b0338a935f97e19191634b06f6a709a988ba 100644
--- a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/ToolbarItemConditionsMetConstraint.php
+++ b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/ToolbarItemConditionsMetConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * A (placed) CKEditor 5 toolbar item's conditions must be met.
@@ -17,7 +17,7 @@
   id: 'CKEditor5ToolbarItemConditionsMet',
   label: new TranslatableMarkup('CKEditor 5 toolbar item conditions must be met', [], ['context' => 'Validation'])
 )]
-class ToolbarItemConditionsMetConstraint extends SymfonyConstraint {
+class ToolbarItemConditionsMetConstraint extends ConstraintBase {
 
   /**
    * The violation message when the required image upload status is not set.
diff --git a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/ToolbarItemConstraint.php b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/ToolbarItemConstraint.php
index 695b4d3e50e935816aca8651711a43aaeab9e364..15cf96e87b4a3a42b5ac31fa09f3bebf020cdff8 100644
--- a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/ToolbarItemConstraint.php
+++ b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/ToolbarItemConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * A CKEditor 5 toolbar item.
@@ -17,7 +17,7 @@
   id: 'CKEditor5ToolbarItem',
   label: new TranslatableMarkup('CKEditor 5 toolbar item', [], ['context' => 'Validation'])
 )]
-class ToolbarItemConstraint extends SymfonyConstraint {
+class ToolbarItemConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/ToolbarItemDependencyConstraint.php b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/ToolbarItemDependencyConstraint.php
index 1b2678b88641860a7a0b5db674d3101c7bb1efd3..c20b0a70eae669ab441dee3d52b30aa301af0fa0 100644
--- a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/ToolbarItemDependencyConstraint.php
+++ b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/ToolbarItemDependencyConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * A CKEditor 5 toolbar item.
@@ -17,7 +17,7 @@
   id: 'CKEditor5ToolbarItemDependencyConstraint',
   label: new TranslatableMarkup('CKEditor 5 toolbar item dependency', [], ['context' => 'Validation'])
 )]
-class ToolbarItemDependencyConstraint extends SymfonyConstraint {
+class ToolbarItemDependencyConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/UniqueLabelInListConstraint.php b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/UniqueLabelInListConstraint.php
index e3fe8dca2f36c003053ceb30c89439bdab22eaae..1f7485529b4ac4145f2b60cc6cc5d4e7154a02e8 100644
--- a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/UniqueLabelInListConstraint.php
+++ b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/UniqueLabelInListConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Uniquely labeled list item constraint.
@@ -17,7 +17,7 @@
   id: 'UniqueLabelInList',
   label: new TranslatableMarkup('Unique label in list', [], ['context' => 'Validation'])
 )]
-class UniqueLabelInListConstraint extends SymfonyConstraint {
+class UniqueLabelInListConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/content_moderation/src/Plugin/Validation/Constraint/ModerationStateConstraint.php b/core/modules/content_moderation/src/Plugin/Validation/Constraint/ModerationStateConstraint.php
index 9dd2b6ab9c0f0720940f311c803ef98252840f4d..19cfa94020a5cb12d9a0ef9dea45b846d469da8e 100644
--- a/core/modules/content_moderation/src/Plugin/Validation/Constraint/ModerationStateConstraint.php
+++ b/core/modules/content_moderation/src/Plugin/Validation/Constraint/ModerationStateConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Verifies that nodes have a valid moderation state.
@@ -13,7 +13,7 @@
   id: 'ModerationState',
   label: new TranslatableMarkup('Valid moderation state', [], ['context' => 'Validation'])
 )]
-class ModerationStateConstraint extends SymfonyConstraint {
+class ModerationStateConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/content_translation/src/Plugin/Validation/Constraint/ContentTranslationSynchronizedFieldsConstraint.php b/core/modules/content_translation/src/Plugin/Validation/Constraint/ContentTranslationSynchronizedFieldsConstraint.php
index 77b1d060bf886b7e910a05328b7364306f75351c..7c18cd6a97a001bb730afcbdaa1489afd3440eec 100644
--- a/core/modules/content_translation/src/Plugin/Validation/Constraint/ContentTranslationSynchronizedFieldsConstraint.php
+++ b/core/modules/content_translation/src/Plugin/Validation/Constraint/ContentTranslationSynchronizedFieldsConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validation constraint for the entity changed timestamp.
@@ -16,7 +16,7 @@
   label: new TranslatableMarkup('Content translation synchronized fields', [], ['context' => 'Validation']),
   type: ['entity']
 )]
-class ContentTranslationSynchronizedFieldsConstraint extends SymfonyConstraint {
+class ContentTranslationSynchronizedFieldsConstraint extends ConstraintBase {
 
   /**
    * Message shown for non-translatable field changes in non-default revision.
diff --git a/core/modules/datetime/src/Plugin/Validation/Constraint/DateTimeFormatConstraint.php b/core/modules/datetime/src/Plugin/Validation/Constraint/DateTimeFormatConstraint.php
index 610f39bfb6b352dce6316a9f5c3517147fc9ad90..c887caf8016e689aa4a304e8089363a0f552a959 100644
--- a/core/modules/datetime/src/Plugin/Validation/Constraint/DateTimeFormatConstraint.php
+++ b/core/modules/datetime/src/Plugin/Validation/Constraint/DateTimeFormatConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validation constraint for DateTime items to ensure the format is correct.
@@ -13,7 +13,7 @@
   id: 'DateTimeFormat',
   label: new TranslatableMarkup('Datetime format valid for datetime type.', [], ['context' => 'Validation'])
 )]
-class DateTimeFormatConstraint extends SymfonyConstraint {
+class DateTimeFormatConstraint extends ConstraintBase {
 
   /**
    * Message for when the value isn't a string.
diff --git a/core/modules/editor/src/Entity/Editor.php b/core/modules/editor/src/Entity/Editor.php
index 8dbf85868bc613d5c32053f8b00857075ec80315..13183d170549ddfd16773b865a4433acd97a627f 100644
--- a/core/modules/editor/src/Entity/Editor.php
+++ b/core/modules/editor/src/Entity/Editor.php
@@ -36,7 +36,7 @@
   ],
   constraints: [
     'RequiredConfigDependencies' => [
-      'filter_format',
+      'entityTypes' => ['filter_format'],
     ],
   ],
   config_export: [
diff --git a/core/modules/field/src/Entity/FieldConfig.php b/core/modules/field/src/Entity/FieldConfig.php
index c27ca0ef272ce4903e031b0df38de1884c5069e9..05c70b90ed64fe86b69d3043cefeb9e5609b09e4 100644
--- a/core/modules/field/src/Entity/FieldConfig.php
+++ b/core/modules/field/src/Entity/FieldConfig.php
@@ -36,13 +36,15 @@
     'plural' => '@count fields',
   ],
   constraints: [
-    'RequiredConfigDependencies' => ['field_storage_config'],
+    'RequiredConfigDependencies' => ['entityTypes' => ['field_storage_config']],
     'ImmutableProperties' => [
-      'id',
-      'entity_type',
-      'field_name',
-      'bundle',
-      'field_type',
+      'properties' => [
+        'id',
+        'entity_type',
+        'field_name',
+        'bundle',
+        'field_type',
+      ],
     ],
   ],
   config_export: [
diff --git a/core/modules/field/src/Entity/FieldStorageConfig.php b/core/modules/field/src/Entity/FieldStorageConfig.php
index b9cca0f1fa23a414c5f0f1681cd8d855815f8b2b..656692d437a5e76b024feffd6c7b065ce972ad11 100644
--- a/core/modules/field/src/Entity/FieldStorageConfig.php
+++ b/core/modules/field/src/Entity/FieldStorageConfig.php
@@ -41,10 +41,12 @@
   ],
   constraints: [
     'ImmutableProperties' => [
-      'id',
-      'entity_type',
-      'field_name',
-      'type',
+      'properties' => [
+        'id',
+        'entity_type',
+        'field_name',
+        'type',
+      ],
     ],
   ],
   config_export: [
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
index 9e89b21e9e772559fb3de22bc22b9b85f208ca9b..1f596b216caa81656eae216322eab23ce2967425 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
@@ -126,14 +126,16 @@ public function getConstraints() {
     $constraints = parent::getConstraints();
 
     $constraints[] = $constraint_manager->create('ComplexData', [
-      'value' => [
-        'TestField' => [
-          'value' => -1,
-          'message' => $this->t('%name does not accept the value @value.', [
-            '%name' => $this->getFieldDefinition()
-              ->getLabel(),
-            '@value' => -1,
-          ]),
+      'properties' => [
+        'value' => [
+          'TestField' => [
+            'value' => -1,
+            'message' => $this->t('%name does not accept the value @value.', [
+              '%name' => $this->getFieldDefinition()
+                ->getLabel(),
+              '@value' => -1,
+            ]),
+          ],
         ],
       ],
     ]);
diff --git a/core/modules/file/src/Plugin/Validation/Constraint/FileEncodingConstraint.php b/core/modules/file/src/Plugin/Validation/Constraint/FileEncodingConstraint.php
index 5416fd760423c37abb1a699d3fb242be3e4fdad8..1628852eda99f2da4d7b9e99e83616d6b9f4208c 100644
--- a/core/modules/file/src/Plugin/Validation/Constraint/FileEncodingConstraint.php
+++ b/core/modules/file/src/Plugin/Validation/Constraint/FileEncodingConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Defines an encoding constraint for files.
@@ -15,7 +15,7 @@
   id: 'FileEncoding',
   label: new TranslatableMarkup('File encoding', [], ['context' => 'Validation'])
 )]
-class FileEncodingConstraint extends SymfonyConstraint {
+class FileEncodingConstraint extends ConstraintBase {
 
   /**
    * The error message.
diff --git a/core/modules/file/src/Plugin/Validation/Constraint/FileExtensionConstraint.php b/core/modules/file/src/Plugin/Validation/Constraint/FileExtensionConstraint.php
index 88e684283692c6164bc6183c85c2486a56773d8d..28221a3f09ad43e3b32cb04c32ef6207ba1e8922 100644
--- a/core/modules/file/src/Plugin/Validation/Constraint/FileExtensionConstraint.php
+++ b/core/modules/file/src/Plugin/Validation/Constraint/FileExtensionConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * File extension constraint.
@@ -16,7 +16,7 @@
   label: new TranslatableMarkup('File Extension', [], ['context' => 'Validation']),
   type: 'file'
 )]
-class FileExtensionConstraint extends SymfonyConstraint {
+class FileExtensionConstraint extends ConstraintBase {
 
   /**
    * The error message.
diff --git a/core/modules/file/src/Plugin/Validation/Constraint/FileExtensionSecureConstraint.php b/core/modules/file/src/Plugin/Validation/Constraint/FileExtensionSecureConstraint.php
index 056c5fc393c57b775280b81b87d5277c3544ed76..661217ebca6418538bd4a3bef1b19dce5fcbc534 100644
--- a/core/modules/file/src/Plugin/Validation/Constraint/FileExtensionSecureConstraint.php
+++ b/core/modules/file/src/Plugin/Validation/Constraint/FileExtensionSecureConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * File extension secure constraint.
@@ -16,7 +16,7 @@
   label: new TranslatableMarkup('File Extension Secure', [], ['context' => 'Validation']),
   type: 'file'
 )]
-class FileExtensionSecureConstraint extends SymfonyConstraint {
+class FileExtensionSecureConstraint extends ConstraintBase {
 
   /**
    * The error message.
diff --git a/core/modules/file/src/Plugin/Validation/Constraint/FileImageDimensionsConstraint.php b/core/modules/file/src/Plugin/Validation/Constraint/FileImageDimensionsConstraint.php
index 3fe13b9aedf802de3d64908eca0c0524c75a80c0..8549d97c1cbc61f18ace152a5478315606468292 100644
--- a/core/modules/file/src/Plugin/Validation/Constraint/FileImageDimensionsConstraint.php
+++ b/core/modules/file/src/Plugin/Validation/Constraint/FileImageDimensionsConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * File extension dimensions constraint.
@@ -16,7 +16,7 @@
   label: new TranslatableMarkup('File Image Dimensions', [], ['context' => 'Validation']),
   type: 'file'
 )]
-class FileImageDimensionsConstraint extends SymfonyConstraint {
+class FileImageDimensionsConstraint extends ConstraintBase {
 
   /**
    * The minimum dimensions.
diff --git a/core/modules/file/src/Plugin/Validation/Constraint/FileIsImageConstraint.php b/core/modules/file/src/Plugin/Validation/Constraint/FileIsImageConstraint.php
index a63a7470fbcb70b5aef45d660b5523c72118a66c..0c85857e15c827c045438981e68c4a9b6ef44364 100644
--- a/core/modules/file/src/Plugin/Validation/Constraint/FileIsImageConstraint.php
+++ b/core/modules/file/src/Plugin/Validation/Constraint/FileIsImageConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * File is image constraint.
@@ -16,7 +16,7 @@
   label: new TranslatableMarkup('File Is Image', [], ['context' => 'Validation']),
   type: 'file'
 )]
-class FileIsImageConstraint extends SymfonyConstraint {
+class FileIsImageConstraint extends ConstraintBase {
 
   /**
    * The error message.
diff --git a/core/modules/file/src/Plugin/Validation/Constraint/FileNameLengthConstraint.php b/core/modules/file/src/Plugin/Validation/Constraint/FileNameLengthConstraint.php
index cd541cc9495d76c177f2ec896fa0adb9296f58b1..05f1f77ce797c84839c9244f242846e5daf9cd90 100644
--- a/core/modules/file/src/Plugin/Validation/Constraint/FileNameLengthConstraint.php
+++ b/core/modules/file/src/Plugin/Validation/Constraint/FileNameLengthConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * File name length constraint.
@@ -14,7 +14,7 @@
   label: new TranslatableMarkup('File Name Length', [], ['context' => 'Validation']),
   type: 'file'
 )]
-class FileNameLengthConstraint extends SymfonyConstraint {
+class FileNameLengthConstraint extends ConstraintBase {
 
   /**
    * The maximum file name length.
diff --git a/core/modules/file/src/Plugin/Validation/Constraint/FileSizeLimitConstraint.php b/core/modules/file/src/Plugin/Validation/Constraint/FileSizeLimitConstraint.php
index 1b8ca0d20e030f08b7b249e9dc084bea90300c0f..63d62c9e17b976d287b46ebd45a3590d56d616cb 100644
--- a/core/modules/file/src/Plugin/Validation/Constraint/FileSizeLimitConstraint.php
+++ b/core/modules/file/src/Plugin/Validation/Constraint/FileSizeLimitConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * File size max constraint.
@@ -14,7 +14,7 @@
   label: new TranslatableMarkup('File Size Limit', [], ['context' => 'Validation']),
   type: 'file'
 )]
-class FileSizeLimitConstraint extends SymfonyConstraint {
+class FileSizeLimitConstraint extends ConstraintBase {
 
   /**
    * The message for when file size limit is exceeded.
diff --git a/core/modules/file/src/Plugin/Validation/Constraint/FileValidationConstraint.php b/core/modules/file/src/Plugin/Validation/Constraint/FileValidationConstraint.php
index 2ed9c9f884e79db9593771e51b46e3bb970b1f0c..e44d4583ec09998212e20564d020d5b46225689a 100644
--- a/core/modules/file/src/Plugin/Validation/Constraint/FileValidationConstraint.php
+++ b/core/modules/file/src/Plugin/Validation/Constraint/FileValidationConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validation File constraint.
@@ -13,6 +13,6 @@
   id: 'FileValidation',
   label: new TranslatableMarkup('File Validation', [], ['context' => 'Validation'])
 )]
-class FileValidationConstraint extends SymfonyConstraint {
+class FileValidationConstraint extends ConstraintBase {
 
 }
diff --git a/core/modules/image/tests/modules/image_field_property_constraint_validation/src/Plugin/Validation/Constraint/AltTextContainsLlamasConstraint.php b/core/modules/image/tests/modules/image_field_property_constraint_validation/src/Plugin/Validation/Constraint/AltTextContainsLlamasConstraint.php
index 2fe6847eff14ebee45afefdb08efa8c53af5fc7b..96c95bb5c26e24f97d479f7d4ebff66b5c97b491 100644
--- a/core/modules/image/tests/modules/image_field_property_constraint_validation/src/Plugin/Validation/Constraint/AltTextContainsLlamasConstraint.php
+++ b/core/modules/image/tests/modules/image_field_property_constraint_validation/src/Plugin/Validation/Constraint/AltTextContainsLlamasConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Provides a Contains Llamas constraint.
@@ -15,7 +15,7 @@
   id: 'AltTextContainsLlamas',
   label: new TranslatableMarkup('Contains Llamas', options: ['context' => 'Validation'])
 )]
-final class AltTextContainsLlamasConstraint extends SymfonyConstraint {
+final class AltTextContainsLlamasConstraint extends ConstraintBase {
 
   /**
    * The error message.
diff --git a/core/modules/language/config/schema/language.schema.yml b/core/modules/language/config/schema/language.schema.yml
index f7ddf9f08584fd19b6ba06a7890d1ff37f5a5ee1..f3bf7bbd9d35f605db78eda226542ce01773e2c1 100644
--- a/core/modules/language/config/schema/language.schema.yml
+++ b/core/modules/language/config/schema/language.schema.yml
@@ -138,7 +138,8 @@ language.content_settings.*.*:
       type:  string
       label: 'Bundle'
       constraints:
-        EntityBundleExists: '%parent.target_entity_type_id'
+        EntityBundleExists:
+          entityTypeId: '%parent.target_entity_type_id'
     default_langcode:
       type: langcode
       label: 'Default language'
diff --git a/core/modules/language/src/Entity/ContentLanguageSettings.php b/core/modules/language/src/Entity/ContentLanguageSettings.php
index 16506f04b26d61de17692ea750b1e87b5eb29088..ce5b61904df83d223bdbdd7b6ee4631239c412e9 100644
--- a/core/modules/language/src/Entity/ContentLanguageSettings.php
+++ b/core/modules/language/src/Entity/ContentLanguageSettings.php
@@ -34,9 +34,11 @@
   ],
   constraints: [
     'ImmutableProperties' => [
-      'id',
-      'target_entity_type_id',
-      'target_bundle',
+      'properties' => [
+        'id',
+        'target_entity_type_id',
+        'target_bundle',
+      ],
     ],
   ],
   config_export: [
diff --git a/core/modules/layout_builder/src/Plugin/Derivative/ExtraFieldBlockDeriver.php b/core/modules/layout_builder/src/Plugin/Derivative/ExtraFieldBlockDeriver.php
index 9a0dd6a9782cdb5b8ed54d669bfe9035cb730975..20cbac90a689aa185980319b29a51e5f856616dd 100644
--- a/core/modules/layout_builder/src/Plugin/Derivative/ExtraFieldBlockDeriver.php
+++ b/core/modules/layout_builder/src/Plugin/Derivative/ExtraFieldBlockDeriver.php
@@ -132,7 +132,7 @@ public function getDerivativeDefinitions($base_plugin_definition) {
           $derivative['admin_label'] = $extra_field['label'];
 
           $context_definition = EntityContextDefinition::fromEntityType($entity_type)
-            ->addConstraint('Bundle', [$bundle_id]);
+            ->addConstraint('Bundle', ['bundle' => [$bundle_id]]);
           $derivative['context_definitions'] = [
             'entity' => $context_definition,
           ];
diff --git a/core/modules/layout_builder/src/Plugin/Derivative/FieldBlockDeriver.php b/core/modules/layout_builder/src/Plugin/Derivative/FieldBlockDeriver.php
index e01a03002012fab2e967ca5948d38f524032c429..a4440c20f7f84722d00b8d698a7d641547ee9403 100644
--- a/core/modules/layout_builder/src/Plugin/Derivative/FieldBlockDeriver.php
+++ b/core/modules/layout_builder/src/Plugin/Derivative/FieldBlockDeriver.php
@@ -143,7 +143,7 @@ public function getDerivativeDefinitions($base_plugin_definition) {
           $derivative['_block_ui_hidden'] = !$field_definition->isDisplayConfigurable('view');
 
           $context_definition = EntityContextDefinition::fromEntityTypeId($entity_type_id)->setLabel($entity_type_labels[$entity_type_id]);
-          $context_definition->addConstraint('Bundle', [$bundle]);
+          $context_definition->addConstraint('Bundle', ['bundle' => [$bundle]]);
           $derivative['context_definitions'] = [
             'entity' => $context_definition,
             'view_mode' => new ContextDefinition('string'),
diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php b/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
index 7fc7491fb85b14eb0593ef249eb7fc69acc83654..7e002530f28f8f7e729b22b673b67f215ce7f101 100644
--- a/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
+++ b/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
@@ -44,7 +44,7 @@
       data_type: 'entity',
       label: new TranslatableMarkup("Entity"),
       constraints: [
-        "EntityHasField" => OverridesSectionStorage::FIELD_NAME,
+        "EntityHasField" => ['field_name' => OverridesSectionStorage::FIELD_NAME],
       ],
     ),
     'view_mode' => new ContextDefinition(
diff --git a/core/modules/link/src/Plugin/Validation/Constraint/LinkAccessConstraint.php b/core/modules/link/src/Plugin/Validation/Constraint/LinkAccessConstraint.php
index 18fe46c4d55f0a2febb9b71a33eb562ca9088785..86c05941f149c129dd4efb84ecfad842ca682d2c 100644
--- a/core/modules/link/src/Plugin/Validation/Constraint/LinkAccessConstraint.php
+++ b/core/modules/link/src/Plugin/Validation/Constraint/LinkAccessConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Defines an access validation constraint for links.
@@ -13,7 +13,7 @@
   id: 'LinkAccess',
   label: new TranslatableMarkup('Link URI can be accessed by the user.', [], ['context' => 'Validation'])
 )]
-class LinkAccessConstraint extends SymfonyConstraint {
+class LinkAccessConstraint extends ConstraintBase {
 
   /**
    * The error message.
diff --git a/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraint.php b/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraint.php
index bd383c0c4eb2cacd2c50c09406817067181df5a8..ebf4f8644909b047e88be50878305967519f682b 100644
--- a/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraint.php
+++ b/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Defines a protocol validation constraint for links to external URLs.
@@ -13,7 +13,7 @@
   id: 'LinkExternalProtocols',
   label: new TranslatableMarkup('No dangerous external protocols', [], ['context' => 'Validation'])
 )]
-class LinkExternalProtocolsConstraint extends SymfonyConstraint {
+class LinkExternalProtocolsConstraint extends ConstraintBase {
 
   /**
    * The error message.
diff --git a/core/modules/link/src/Plugin/Validation/Constraint/LinkNotExistingInternalConstraint.php b/core/modules/link/src/Plugin/Validation/Constraint/LinkNotExistingInternalConstraint.php
index 6d25cf00a25fe2a9822f4650b205d01cca4993af..7bd8686433b50925dcb91c589b9d927ddb1e54a3 100644
--- a/core/modules/link/src/Plugin/Validation/Constraint/LinkNotExistingInternalConstraint.php
+++ b/core/modules/link/src/Plugin/Validation/Constraint/LinkNotExistingInternalConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Defines a protocol validation constraint for links to broken internal URLs.
@@ -13,7 +13,7 @@
   id: 'LinkNotExistingInternal',
   label: new TranslatableMarkup('No broken internal links', [], ['context' => 'Validation'])
 )]
-class LinkNotExistingInternalConstraint extends SymfonyConstraint {
+class LinkNotExistingInternalConstraint extends ConstraintBase {
 
   /**
    * The error message.
diff --git a/core/modules/link/src/Plugin/Validation/Constraint/LinkTypeConstraint.php b/core/modules/link/src/Plugin/Validation/Constraint/LinkTypeConstraint.php
index 83333afdaad2ba9afe75821ecdf8abf9a683e717..eb77dbaff9e352750af7b13de3fa994c068c55f1 100644
--- a/core/modules/link/src/Plugin/Validation/Constraint/LinkTypeConstraint.php
+++ b/core/modules/link/src/Plugin/Validation/Constraint/LinkTypeConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validation constraint for links receiving data allowed by its settings.
@@ -13,7 +13,7 @@
   id: 'LinkType',
   label: new TranslatableMarkup('Link data valid for link type.', [], ['context' => 'Validation'])
 )]
-class LinkTypeConstraint extends SymfonyConstraint {
+class LinkTypeConstraint extends ConstraintBase {
 
   /**
    * The error message.
diff --git a/core/modules/media/src/Entity/MediaType.php b/core/modules/media/src/Entity/MediaType.php
index b2026cc2dd8b75334fd0033cc5303c54768411f0..b4716c248f668bc1d4451e6ae9c903e36655f72e 100644
--- a/core/modules/media/src/Entity/MediaType.php
+++ b/core/modules/media/src/Entity/MediaType.php
@@ -59,8 +59,10 @@
   ],
   constraints: [
     'ImmutableProperties' => [
-      'id',
-      'source',
+      'properties' => [
+        'id',
+        'source',
+      ],
     ],
     'MediaMappingsConstraint' => [],
   ],
diff --git a/core/modules/media/src/Plugin/Validation/Constraint/MediaMappingsConstraint.php b/core/modules/media/src/Plugin/Validation/Constraint/MediaMappingsConstraint.php
index 17a2e6df40810db11b41079f240cf70923a29423..5f948e22e2c924d38e8823b4f997087de78dfabe 100644
--- a/core/modules/media/src/Plugin/Validation/Constraint/MediaMappingsConstraint.php
+++ b/core/modules/media/src/Plugin/Validation/Constraint/MediaMappingsConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\Validation\Attribute\Constraint;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validates media mappings.
@@ -16,7 +16,7 @@
   label: new TranslatableMarkup('Media Mapping Constraint', [], ['context' => 'Validation']),
   type: 'string'
 )]
-class MediaMappingsConstraint extends SymfonyConstraint {
+class MediaMappingsConstraint extends ConstraintBase {
 
   /**
    * The error message if source is used in media mapping.
diff --git a/core/modules/media/src/Plugin/Validation/Constraint/OEmbedResourceConstraint.php b/core/modules/media/src/Plugin/Validation/Constraint/OEmbedResourceConstraint.php
index dcde3c8709563050a0595d0962dd847a1407c9ac..1b7a78835840f1e2e9e8f2016991e90b6bfb940b 100644
--- a/core/modules/media/src/Plugin/Validation/Constraint/OEmbedResourceConstraint.php
+++ b/core/modules/media/src/Plugin/Validation/Constraint/OEmbedResourceConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Checks if a value represents a valid oEmbed resource URL.
@@ -18,7 +18,7 @@
   label: new TranslatableMarkup('oEmbed resource', [], ['context' => 'Validation']),
   type: ['link', 'string', 'string_long']
 )]
-class OEmbedResourceConstraint extends SymfonyConstraint {
+class OEmbedResourceConstraint extends ConstraintBase {
 
   /**
    * The error message if the URL does not match any known provider.
diff --git a/core/modules/media/tests/modules/media_test_source/src/Plugin/Validation/Constraint/MediaTestConstraint.php b/core/modules/media/tests/modules/media_test_source/src/Plugin/Validation/Constraint/MediaTestConstraint.php
index 50290eb9b036c2ca532721ac2e48887b8dd3c681..894a9dc17232ad5939e7c6aa9cda704eb97c56df 100644
--- a/core/modules/media/tests/modules/media_test_source/src/Plugin/Validation/Constraint/MediaTestConstraint.php
+++ b/core/modules/media/tests/modules/media_test_source/src/Plugin/Validation/Constraint/MediaTestConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * A media test constraint.
@@ -16,7 +16,7 @@
   label: new TranslatableMarkup('Media constraint for test purposes.', [], ['context' => 'Validation']),
   type: ['entity', 'string']
 )]
-class MediaTestConstraint extends SymfonyConstraint {
+class MediaTestConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraint.php b/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraint.php
index 0a379096e0acdb1389987b086ba4ecde4c3d5caf..b7d05a66cc87a2a1a945725e525d1fe3ddc7c4de 100644
--- a/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraint.php
+++ b/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validation constraint for changing the menu settings in pending revisions.
@@ -13,7 +13,7 @@
   id: 'MenuSettings',
   label: new TranslatableMarkup('Menu settings.', [], ['context' => 'Validation'])
 )]
-class MenuSettingsConstraint extends SymfonyConstraint {
+class MenuSettingsConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/navigation/config/schema/navigation.schema.yml b/core/modules/navigation/config/schema/navigation.schema.yml
index ee31849202a077c94decea16323edd29486393cf..a83eca34eb965b523280df5dbe401bbd69ab0e5c 100644
--- a/core/modules/navigation/config/schema/navigation.schema.yml
+++ b/core/modules/navigation/config/schema/navigation.schema.yml
@@ -49,9 +49,11 @@ navigation.settings:
                 Range:
                   min: 0
           constraints:
-            ValidKeys: '<infer>'
+            ValidKeys:
+              allowedKeys: '<infer>'
       constraints:
-        ValidKeys: '<infer>'
+        ValidKeys:
+          allowedKeys: '<infer>'
 
 navigation.block_layout:
   type: config_object
diff --git a/core/modules/path/src/Plugin/Validation/Constraint/PathAliasConstraint.php b/core/modules/path/src/Plugin/Validation/Constraint/PathAliasConstraint.php
index 636aeeca101d7efd5f8da4fe2e5f982bc7bfebab..e8ae960661fc8949437d506ce92618937f832a56 100644
--- a/core/modules/path/src/Plugin/Validation/Constraint/PathAliasConstraint.php
+++ b/core/modules/path/src/Plugin/Validation/Constraint/PathAliasConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validation constraint for changing path aliases in pending revisions.
@@ -13,7 +13,7 @@
   id: 'PathAlias',
   label: new TranslatableMarkup('Path alias.', [], ['context' => 'Validation'])
 )]
-class PathAliasConstraint extends SymfonyConstraint {
+class PathAliasConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/rest/tests/modules/rest_test/src/Plugin/Validation/Constraint/RestTestConstraint.php b/core/modules/rest/tests/modules/rest_test/src/Plugin/Validation/Constraint/RestTestConstraint.php
index 9c9e94afe7a5096dbc5635b1b4b87b9326fcccc7..db0ccc7aa05f7364564fcb79d6464dccb6a12809 100644
--- a/core/modules/rest/tests/modules/rest_test/src/Plugin/Validation/Constraint/RestTestConstraint.php
+++ b/core/modules/rest/tests/modules/rest_test/src/Plugin/Validation/Constraint/RestTestConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Adds some validations for a REST test field.
@@ -17,7 +17,7 @@
   id: 'rest_test_validation',
   label: new TranslatableMarkup('REST test validation', [], ['context' => 'Validation'])
 )]
-class RestTestConstraint extends SymfonyConstraint {
+class RestTestConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/system/src/SecurityAdvisories/SecurityAdvisory.php b/core/modules/system/src/SecurityAdvisories/SecurityAdvisory.php
index 4ff3768c1ce419ddaa0de5b830370a772fb13e7f..b6d8a094fe7b4ac4ba7627b0f5b5b42b4c95b753 100644
--- a/core/modules/system/src/SecurityAdvisories/SecurityAdvisory.php
+++ b/core/modules/system/src/SecurityAdvisories/SecurityAdvisory.php
@@ -120,22 +120,22 @@ public static function createFromArray(array $data): self {
    */
   protected static function validateAdvisoryData(array $data): void {
     $not_blank_constraints = [
-      new Type(['type' => 'string']),
+      new Type(type: 'string'),
       new NotBlank(),
     ];
-    $collection_constraint = new Collection([
-      'fields' => [
+    $collection_constraint = new Collection(
+      fields: [
         'title' => $not_blank_constraints,
         'project' => $not_blank_constraints,
         'type' => $not_blank_constraints,
         'link' => $not_blank_constraints,
-        'is_psa' => new Choice(['choices' => [1, '1', 0, '0', TRUE, FALSE]]),
-        'insecure' => new Type(['type' => 'array']),
+        'is_psa' => new Choice(choices: [1, '1', 0, '0', TRUE, FALSE]),
+        'insecure' => new Type(type: 'array'),
       ],
       // Allow unknown fields, in the case that new fields are added to JSON
       // feed validation should still pass.
-      'allowExtraFields' => TRUE,
-    ]);
+      allowExtraFields:TRUE,
+    );
     $violations = Validation::createValidator()->validate($data, $collection_constraint);
     if ($violations->count()) {
       foreach ($violations as $violation) {
diff --git a/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/EntityTestEntityLevel.php b/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/EntityTestEntityLevel.php
index 956c032b5d5962e16fd01465fe96ac863165e8b2..a1bba9062f1710544f3eb7d46c1a661b068a7b61 100644
--- a/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/EntityTestEntityLevel.php
+++ b/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/EntityTestEntityLevel.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Constraint on entity level.
@@ -16,7 +16,7 @@
   label: new TranslatableMarkup('Constraint on the entity level.'),
   type: ['entity']
 )]
-class EntityTestEntityLevel extends SymfonyConstraint {
+class EntityTestEntityLevel extends ConstraintBase {
 
   /**
    * The error message.
diff --git a/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/FieldWidgetConstraint.php b/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/FieldWidgetConstraint.php
index 88f3be980aa2084f9557f1cdb7637b8f429909e5..c542967df511e3e14b6378118c4e322fbf23cdc7 100644
--- a/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/FieldWidgetConstraint.php
+++ b/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/FieldWidgetConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Supports validating widget constraints.
@@ -15,7 +15,7 @@
   id: 'FieldWidgetConstraint',
   label: new TranslatableMarkup('Field widget constraint.')
 )]
-class FieldWidgetConstraint extends SymfonyConstraint {
+class FieldWidgetConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/TestValidatedReferenceConstraint.php b/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/TestValidatedReferenceConstraint.php
index 180799237ff5aa1c6ded76bee9363256042e130c..5e678d777d75fe02c5c401ff4ed3b37c56299fcf 100644
--- a/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/TestValidatedReferenceConstraint.php
+++ b/core/modules/system/tests/modules/entity_test/src/Plugin/Validation/Constraint/TestValidatedReferenceConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validates referenced entities.
@@ -15,7 +15,7 @@
   id: 'TestValidatedReferenceConstraint',
   label: new TranslatableMarkup('Test validated reference constraint.')
 )]
-class TestValidatedReferenceConstraint extends SymfonyConstraint {
+class TestValidatedReferenceConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/telephone/src/Plugin/Field/FieldType/TelephoneItem.php b/core/modules/telephone/src/Plugin/Field/FieldType/TelephoneItem.php
index dd97b961d14d560e636cae0c16e4c242fd8fc050..a913e834f17029f380ef8c40367cceecd52c9f66 100644
--- a/core/modules/telephone/src/Plugin/Field/FieldType/TelephoneItem.php
+++ b/core/modules/telephone/src/Plugin/Field/FieldType/TelephoneItem.php
@@ -67,10 +67,12 @@ public function getConstraints() {
     $constraints = parent::getConstraints();
 
     $constraints[] = $constraint_manager->create('ComplexData', [
-      'value' => [
-        'Length' => [
-          'max' => self::MAX_LENGTH,
-          'maxMessage' => $this->t('%name: the telephone number may not be longer than @max characters.', ['%name' => $this->getFieldDefinition()->getLabel(), '@max' => self::MAX_LENGTH]),
+      'properties' => [
+        'value' => [
+          'Length' => [
+            'max' => self::MAX_LENGTH,
+            'maxMessage' => $this->t('%name: the telephone number may not be longer than @max characters.', ['%name' => $this->getFieldDefinition()->getLabel(), '@max' => self::MAX_LENGTH]),
+          ],
         ],
       ],
     ]);
diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextItem.php b/core/modules/text/src/Plugin/Field/FieldType/TextItem.php
index 5d3ac034b34674f197b7287c8061abc2f571115b..956fc0fd5dcd7f9b378217937911f8f5e0755655 100644
--- a/core/modules/text/src/Plugin/Field/FieldType/TextItem.php
+++ b/core/modules/text/src/Plugin/Field/FieldType/TextItem.php
@@ -65,10 +65,12 @@ public function getConstraints() {
 
     if ($max_length = $this->getSetting('max_length')) {
       $constraints[] = $constraint_manager->create('ComplexData', [
-        'value' => [
-          'Length' => [
-            'max' => $max_length,
-            'maxMessage' => $this->t('%name: the text may not be longer than @max characters.', ['%name' => $this->getFieldDefinition()->getLabel(), '@max' => $max_length]),
+        'properties' => [
+          'value' => [
+            'Length' => [
+              'max' => $max_length,
+              'maxMessage' => $this->t('%name: the text may not be longer than @max characters.', ['%name' => $this->getFieldDefinition()->getLabel(), '@max' => $max_length]),
+            ],
           ],
         ],
       ]);
diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php b/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php
index f099a53a93c2aa10ee6b0103fdf13521292236ac..a280501fd360ca743327ce69cceafe3773eec0f2 100644
--- a/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php
+++ b/core/modules/text/src/Plugin/Field/FieldType/TextWithSummaryItem.php
@@ -121,9 +121,11 @@ public function getConstraints() {
     if ($this->getSetting('required_summary')) {
       $manager = $this->getTypedDataManager()->getValidationConstraintManager();
       $constraints[] = $manager->create('ComplexData', [
-        'summary' => [
-          'NotNull' => [
-            'message' => $this->t('The summary field is required for @name', ['@name' => $this->getFieldDefinition()->getLabel()]),
+        'properties' => [
+          'summary' => [
+            'NotNull' => [
+              'message' => $this->t('The summary field is required for @name', ['@name' => $this->getFieldDefinition()->getLabel()]),
+            ],
           ],
         ],
       ]);
diff --git a/core/modules/update/src/ProjectRelease.php b/core/modules/update/src/ProjectRelease.php
index 899eb9b836f78e28edf59452d9d9adfc90c074cc..8c3532fbc4f1a0ba93de23d8f6e84c392ce37e3e 100644
--- a/core/modules/update/src/ProjectRelease.php
+++ b/core/modules/update/src/ProjectRelease.php
@@ -143,8 +143,8 @@ private static function validateReleaseData(array $data): void {
       new Type('string'),
       new NotBlank(),
     ];
-    $collection_constraint = new Collection([
-      'fields' => [
+    $collection_constraint = new Collection(
+      fields: [
         'version' => $not_blank_constraints,
         'date' => new Optional([new Type('numeric')]),
         'core_compatible' => new Optional([new Type('boolean')]),
@@ -161,8 +161,8 @@ private static function validateReleaseData(array $data): void {
           ]),
         ]),
       ],
-      'allowExtraFields' => TRUE,
-    ]);
+      allowExtraFields:TRUE,
+    );
     $violations = Validation::createValidator()->validate($data, $collection_constraint);
     if (count($violations)) {
       foreach ($violations as $violation) {
diff --git a/core/modules/user/src/Plugin/Validation/Constraint/ProtectedUserFieldConstraint.php b/core/modules/user/src/Plugin/Validation/Constraint/ProtectedUserFieldConstraint.php
index bb112e0a593a98402004231f3f94c14b439f8883..a98e5a735a4b2132b2de4de9946a148a2625adfd 100644
--- a/core/modules/user/src/Plugin/Validation/Constraint/ProtectedUserFieldConstraint.php
+++ b/core/modules/user/src/Plugin/Validation/Constraint/ProtectedUserFieldConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Checks if the plain text password is provided for editing a protected field.
@@ -13,7 +13,7 @@
   id: 'ProtectedUserField',
   label: new TranslatableMarkup('Password required for protected field change', [], ['context' => 'Validation'])
 )]
-class ProtectedUserFieldConstraint extends SymfonyConstraint {
+class ProtectedUserFieldConstraint extends ConstraintBase {
 
   /**
    * Violation message.
diff --git a/core/modules/user/src/Plugin/Validation/Constraint/RoleExistsConstraint.php b/core/modules/user/src/Plugin/Validation/Constraint/RoleExistsConstraint.php
index 790cfc0f2ba726032821b3e3a5991cce8de26fb0..31f5181d8965496fa3aaf56f1c512afe78165a66 100644
--- a/core/modules/user/src/Plugin/Validation/Constraint/RoleExistsConstraint.php
+++ b/core/modules/user/src/Plugin/Validation/Constraint/RoleExistsConstraint.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Checks if a role exists.
@@ -15,7 +15,7 @@
   id: 'RoleExists',
   label: new TranslatableMarkup('Role exists', [], ['context' => 'Validation'])
 )]
-class RoleExistsConstraint extends SymfonyConstraint {
+class RoleExistsConstraint extends ConstraintBase {
 
   /**
    * The error message if validation fails.
diff --git a/core/modules/user/src/Plugin/Validation/Constraint/UserCancelMethodsConstraint.php b/core/modules/user/src/Plugin/Validation/Constraint/UserCancelMethodsConstraint.php
index 44034b3d3db291947c3dafa251205ad223e2f7b0..f21af4ac4c45eae5ea8257e7be679339c9c2a12d 100644
--- a/core/modules/user/src/Plugin/Validation/Constraint/UserCancelMethodsConstraint.php
+++ b/core/modules/user/src/Plugin/Validation/Constraint/UserCancelMethodsConstraint.php
@@ -24,7 +24,7 @@ class UserCancelMethodsConstraint implements ContainerFactoryPluginInterface {
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): Choice {
     $configuration['choices'] = array_keys(user_cancel_methods()['#options']);
-    return new Choice($configuration);
+    return new Choice(...$configuration);
   }
 
 }
diff --git a/core/modules/user/src/Plugin/Validation/Constraint/UserMailRequired.php b/core/modules/user/src/Plugin/Validation/Constraint/UserMailRequired.php
index 404ba73e86172b21cdb7c1293b371d78c7badfe6..40c5de6ff65ec38003646ccef057c29ffa12a736 100644
--- a/core/modules/user/src/Plugin/Validation/Constraint/UserMailRequired.php
+++ b/core/modules/user/src/Plugin/Validation/Constraint/UserMailRequired.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Checks if the user's email address is provided if required.
@@ -17,7 +17,7 @@
   id: 'UserMailRequired',
   label: new TranslatableMarkup('User email required', [], ['context' => 'Validation'])
 )]
-class UserMailRequired extends SymfonyConstraint {
+class UserMailRequired extends ConstraintBase {
 
   /**
    * Violation message. Use the same message as FormValidator.
diff --git a/core/modules/user/src/Plugin/Validation/Constraint/UserNameConstraint.php b/core/modules/user/src/Plugin/Validation/Constraint/UserNameConstraint.php
index 8739f0a3f8c6af2f13bf022b9c9099931962280d..4455a3f4b7d9bad4fdde77ab2fa8015981714b6c 100644
--- a/core/modules/user/src/Plugin/Validation/Constraint/UserNameConstraint.php
+++ b/core/modules/user/src/Plugin/Validation/Constraint/UserNameConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Checks if a value is a valid user name.
@@ -13,7 +13,7 @@
   id: 'UserName',
   label: new TranslatableMarkup('User name', [], ['context' => 'Validation'])
 )]
-class UserNameConstraint extends SymfonyConstraint {
+class UserNameConstraint extends ConstraintBase {
 
   /**
    * The violation message when there is no username.
diff --git a/core/modules/workspaces/src/Plugin/Validation/Constraint/DeletedWorkspaceConstraint.php b/core/modules/workspaces/src/Plugin/Validation/Constraint/DeletedWorkspaceConstraint.php
index ecc1c1393d914f10a5a0bc20a014436d3cf5311a..bc6e80635fd801be9bda93fd30de18c2f6614316 100644
--- a/core/modules/workspaces/src/Plugin/Validation/Constraint/DeletedWorkspaceConstraint.php
+++ b/core/modules/workspaces/src/Plugin/Validation/Constraint/DeletedWorkspaceConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Deleted workspace constraint.
@@ -13,7 +13,7 @@
   id: 'DeletedWorkspace',
   label: new TranslatableMarkup('Deleted workspace', [], ['context' => 'Validation'])
 )]
-class DeletedWorkspaceConstraint extends SymfonyConstraint {
+class DeletedWorkspaceConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/workspaces/src/Plugin/Validation/Constraint/EntityReferenceSupportedNewEntitiesConstraint.php b/core/modules/workspaces/src/Plugin/Validation/Constraint/EntityReferenceSupportedNewEntitiesConstraint.php
index 81df97812b6c5018bad53b618da25dee14630dd3..71015ab2e732ba27556d635bbc0729409c48a5b0 100644
--- a/core/modules/workspaces/src/Plugin/Validation/Constraint/EntityReferenceSupportedNewEntitiesConstraint.php
+++ b/core/modules/workspaces/src/Plugin/Validation/Constraint/EntityReferenceSupportedNewEntitiesConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * The entity reference supported new entities constraint.
@@ -13,7 +13,7 @@
   id: 'EntityReferenceSupportedNewEntities',
   label: new TranslatableMarkup('Entity Reference Supported New Entities', [], ['context' => 'Validation'])
 )]
-class EntityReferenceSupportedNewEntitiesConstraint extends SymfonyConstraint {
+class EntityReferenceSupportedNewEntitiesConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/modules/workspaces/src/Plugin/Validation/Constraint/EntityWorkspaceConflictConstraint.php b/core/modules/workspaces/src/Plugin/Validation/Constraint/EntityWorkspaceConflictConstraint.php
index 3b21fe55e05668604cba2b2e3d74043ee92a8ff6..7b0aab6f2f2670e033a2967a7c6bc8276e61d156 100644
--- a/core/modules/workspaces/src/Plugin/Validation/Constraint/EntityWorkspaceConflictConstraint.php
+++ b/core/modules/workspaces/src/Plugin/Validation/Constraint/EntityWorkspaceConflictConstraint.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Validation\Attribute\Constraint;
-use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+use Drupal\Core\Validation\Plugin\Validation\Constraint\ConstraintBase;
 
 /**
  * Validation constraint for an entity being edited in multiple workspaces.
@@ -14,7 +14,7 @@
   label: new TranslatableMarkup('Entity workspace conflict', [], ['context' => 'Validation']),
   type: ['entity']
 )]
-class EntityWorkspaceConflictConstraint extends SymfonyConstraint {
+class EntityWorkspaceConflictConstraint extends ConstraintBase {
 
   /**
    * The default violation message.
diff --git a/core/tests/Drupal/KernelTests/Core/Config/ConfigEntityValidationTestBase.php b/core/tests/Drupal/KernelTests/Core/Config/ConfigEntityValidationTestBase.php
index cb0b3086b141bd0660e4f06a9de1dfe94b3c8506..bfb04761d181c7bc0100f343ab0a16b3afbc1d8d 100644
--- a/core/tests/Drupal/KernelTests/Core/Config/ConfigEntityValidationTestBase.php
+++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigEntityValidationTestBase.php
@@ -472,9 +472,9 @@ public function testLangcode(): void {
    */
   public function testImmutableProperties(array $valid_values = []): void {
     $constraints = $this->entity->getEntityType()->getConstraints();
-    $this->assertNotEmpty($constraints['ImmutableProperties'], 'All config entities should have at least one immutable ID property.');
+    $this->assertNotEmpty($constraints['ImmutableProperties']['properties'], 'All config entities should have at least one immutable ID property.');
 
-    foreach ($constraints['ImmutableProperties'] as $property_name) {
+    foreach ($constraints['ImmutableProperties']['properties'] as $property_name) {
       $original_value = $this->entity->get($property_name);
       $this->entity->set($property_name, $valid_values[$property_name] ?? $this->randomMachineName());
       $this->assertValidationErrors([
@@ -561,7 +561,7 @@ public function testRequiredPropertyValuesMissing(?array $additional_expected_va
 
     // Get the config entity properties that are immutable.
     // @see ::testImmutableProperties()
-    $immutable_properties = $this->entity->getEntityType()->getConstraints()['ImmutableProperties'];
+    $immutable_properties = $this->entity->getEntityType()->getConstraints()['ImmutableProperties']['properties'];
 
     // Config entity properties containing plugin collections are special cases:
     // setting them to NULL would cause them to get out of sync with the plugin
diff --git a/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php b/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php
index 4cd56888088f8e16496210cd3c5f2cb8010bb146..a768abaa287b8391eff225c8340252e2849eb5a1 100644
--- a/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php
@@ -79,7 +79,7 @@ public function testSchemaMapping(): void {
     $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
     $expected['unwrap_for_canonical_representation'] = TRUE;
     $expected['constraints'] = [
-      'ValidKeys' => '<infer>',
+      'ValidKeys' => ['allowedKeys' => '<infer>'],
       'LangcodeRequiredIfTranslatableValues' => NULL,
     ];
     $this->assertEquals($expected, $definition, 'Retrieved the right metadata for configuration with only some schema.');
@@ -132,7 +132,7 @@ public function testSchemaMapping(): void {
     $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
     $expected['unwrap_for_canonical_representation'] = TRUE;
     $expected['constraints'] = [
-      'ValidKeys' => '<infer>',
+      'ValidKeys' => ['allowedKeys' => '<infer>'],
       'FullyValidatable' => NULL,
       'LangcodeRequiredIfTranslatableValues' => NULL,
     ];
@@ -169,7 +169,7 @@ public function testSchemaMapping(): void {
     $expected['type'] = 'config_schema_test.ignore';
     $expected['unwrap_for_canonical_representation'] = TRUE;
     $expected['constraints'] = [
-      'ValidKeys' => '<infer>',
+      'ValidKeys' => ['allowedKeys' => '<infer>'],
       'LangcodeRequiredIfTranslatableValues' => NULL,
     ];
 
@@ -226,7 +226,7 @@ public function testSchemaMapping(): void {
     $expected['mapping']['_core']['requiredKey'] = FALSE;
     $expected['type'] = 'image.style.*';
     $expected['constraints'] = [
-      'ValidKeys' => '<infer>',
+      'ValidKeys' => ['allowedKeys' => '<infer>'],
       'FullyValidatable' => NULL,
     ];
 
@@ -252,7 +252,7 @@ public function testSchemaMapping(): void {
     $expected['mapping']['upscale']['label'] = 'Upscale';
     $expected['type'] = 'image.effect.image_scale';
     $expected['constraints'] = [
-      'ValidKeys' => '<infer>',
+      'ValidKeys' => ['allowedKeys' => '<infer>'],
       'FullyValidatable' => NULL,
     ];
 
@@ -284,7 +284,7 @@ public function testSchemaMapping(): void {
       'integer' => ['type' => 'integer', 'requiredKey' => TRUE],
       'string' => ['type' => 'string', 'requiredKey' => TRUE],
     ];
-    $expected['constraints'] = ['ValidKeys' => '<infer>'];
+    $expected['constraints'] = ['ValidKeys' => ['allowedKeys' => '<infer>']];
     $this->assertEquals($expected, $definition, 'Retrieved the right metadata for config_test.dynamic.third_party:third_party_settings.config_schema_test');
 
     // More complex, several level deep test.
@@ -306,7 +306,7 @@ public function testSchemaMapping(): void {
     $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
     $expected['unwrap_for_canonical_representation'] = TRUE;
     $expected['constraints'] = [
-      'ValidKeys' => '<infer>',
+      'ValidKeys' => ['allowedKeys' => '<infer>'],
       'LangcodeRequiredIfTranslatableValues' => NULL,
     ];
 
@@ -590,7 +590,7 @@ public function testSchemaFallback(): void {
     $expected['mapping']['test_description']['label'] = 'Description';
     $expected['type'] = 'config_schema_test.wildcard_fallback.*';
     $expected['constraints'] = [
-      'ValidKeys' => '<infer>',
+      'ValidKeys' => ['allowedKeys' => '<infer>'],
       'LangcodeRequiredIfTranslatableValues' => NULL,
     ];
 
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/BundleConstraintValidatorTest.php b/core/tests/Drupal/KernelTests/Core/Entity/BundleConstraintValidatorTest.php
index 406de9bb3413faad68bffdf67446e7bfaa0f039f..c1af7242cf845b887d0dbfbeba9a83f1b81e2109 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/BundleConstraintValidatorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/BundleConstraintValidatorTest.php
@@ -56,7 +56,7 @@ public function testValidation(): void {
   protected function assertValidation($bundle): void {
     // Create a typed data definition with a Bundle constraint.
     $definition = DataDefinition::create('entity_reference')
-      ->addConstraint('Bundle', $bundle);
+      ->addConstraint('Bundle', ['bundle' => $bundle]);
 
     // Test the validation.
     $node = $this->container->get('entity_type.manager')->getStorage('node')->create(['type' => 'foo']);
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityBundleExistsConstraintValidatorTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityBundleExistsConstraintValidatorTest.php
index 1981091fafb42ae61207c9c8769fcd7941c5c3d5..237291df3a7776ae3f6001612632b20af62ec73b 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityBundleExistsConstraintValidatorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityBundleExistsConstraintValidatorTest.php
@@ -41,7 +41,7 @@ protected function setUp(): void {
    */
   public function testValueMustBeAString(): void {
     $definition = DataDefinition::create('any')
-      ->addConstraint('EntityBundleExists', 'entity_test_with_bundle');
+      ->addConstraint('EntityBundleExists', ['entityTypeId' => 'entity_test_with_bundle']);
 
     $this->expectException(UnexpectedTypeException::class);
     $this->expectExceptionMessage('Expected argument of type "string", "int" given');
@@ -55,7 +55,7 @@ public function testValueMustBeAString(): void {
    */
   public function testEntityTypeIdIsStatic(): void {
     $definition = DataDefinition::create('string')
-      ->addConstraint('EntityBundleExists', 'entity_test_with_bundle');
+      ->addConstraint('EntityBundleExists', ['entityTypeId' => 'entity_test_with_bundle']);
 
     $violations = $this->container->get('typed_data_manager')
       ->create($definition, 'bar')
@@ -84,7 +84,7 @@ public function testDynamicEntityType(string $constraint_value, string $resolved
 
     $this->assertStringStartsWith('%', $constraint_value);
     $value_definition = DataDefinition::create('string')
-      ->addConstraint('EntityBundleExists', $constraint_value);
+      ->addConstraint('EntityBundleExists', ['entityTypeId' => $constraint_value]);
 
     $parent_definition = MapDataDefinition::create()
       ->setPropertyDefinition('entity_type_id', DataDefinition::create('string'))
@@ -109,7 +109,7 @@ public function testEntityTypeIdFromMultipleParents(): void {
       )
       ->setPropertyDefinition('info2', MapDataDefinition::create()
         ->setPropertyDefinition('bundle', DataDefinition::create('string')
-          ->addConstraint('EntityBundleExists', '%parent.%parent.info.entity_type_id')
+          ->addConstraint('EntityBundleExists', ['entityTypeId' => '%parent.%parent.info.entity_type_id'])
         )
       );
 
@@ -134,7 +134,7 @@ public function testEntityTypeIdFromMultipleParents(): void {
   public function testInvalidEntityTypeId(): void {
     $entity_type_id = $this->randomMachineName();
     $definition = DataDefinition::create('string')
-      ->addConstraint('EntityBundleExists', $entity_type_id);
+      ->addConstraint('EntityBundleExists', ['entityTypeId' => $entity_type_id]);
 
     $violations = $this->container->get('typed_data_manager')
       ->create($definition, 'bar')
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityHasFieldConstraintValidatorTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityHasFieldConstraintValidatorTest.php
index 7f717646e8745009ad7ad7cbe4767bcfbef26c71..26865b64cfc496b36f7618d57d18ed27036c4ee0 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityHasFieldConstraintValidatorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityHasFieldConstraintValidatorTest.php
@@ -33,7 +33,7 @@ protected function setUp(): void {
    */
   public function testValidation(): void {
     $this->state->set('entity_test_constraints.build', [
-      'EntityHasField' => 'body',
+      'EntityHasField' => ['field_name' => 'body'],
     ]);
 
     /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityTypeConstraintValidatorTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityTypeConstraintValidatorTest.php
index b13215255d276cd0d54163a4d30954546b43c790..b47019fb84299c9625e76ae16ebb2a3f109dd40b 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityTypeConstraintValidatorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityTypeConstraintValidatorTest.php
@@ -41,7 +41,7 @@ public function testValidation(): void {
     $entity_type = 'node';
     $definition = DataDefinition::create('entity_reference')
       ->setConstraints([
-        'EntityType' => $entity_type,
+        'EntityType' => ['type' => $entity_type],
       ]
     );
 
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/ImmutablePropertiesConstraintValidatorTest.php b/core/tests/Drupal/KernelTests/Core/Entity/ImmutablePropertiesConstraintValidatorTest.php
index be935baf42a7e66317fb2678964f74594cdfa634..6e25341a90555ad1cc65ce425cef5e06a54bcd1e 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/ImmutablePropertiesConstraintValidatorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/ImmutablePropertiesConstraintValidatorTest.php
@@ -31,7 +31,7 @@ class ImmutablePropertiesConstraintValidatorTest extends KernelTestBase {
    */
   public function testValidatorRequiresAConfigEntity(): void {
     $definition = DataDefinition::createFromDataType('any')
-      ->addConstraint('ImmutableProperties', ['read_only']);
+      ->addConstraint('ImmutableProperties', ['properties' => ['read_only']]);
     $data = $this->container->get(TypedDataManagerInterface::class)
       ->create($definition, 39);
     $this->expectException(UnexpectedValueException::class);
@@ -52,7 +52,7 @@ public function testValidatorRejectsANonExistentProperty(): void {
     $this->assertFalse(property_exists($entity, 'non_existent'));
 
     $definition = DataDefinition::createFromDataType('entity:block_content_type')
-      ->addConstraint('ImmutableProperties', ['non_existent']);
+      ->addConstraint('ImmutableProperties', ['properties' => ['non_existent']]);
 
     $this->expectException(LogicException::class);
     $this->expectExceptionMessage("The entity does not have a 'non_existent' property.");
@@ -71,7 +71,7 @@ public function testValidatedEntityMustHaveAnId(): void {
     $entity->id()->shouldBeCalled();
 
     $definition = DataDefinition::createFromDataType('any')
-      ->addConstraint('ImmutableProperties', ['read_only']);
+      ->addConstraint('ImmutableProperties', ['properties' => ['read_only']]);
     $data = $this->container->get(TypedDataManagerInterface::class)
       ->create($definition, $entity->reveal());
     $this->expectException(LogicException::class);
@@ -91,7 +91,7 @@ public function testImmutablePropertyCannotBeChanged(): void {
     $entity->save();
 
     $definition = DataDefinition::createFromDataType('entity:block_content_type')
-      ->addConstraint('ImmutableProperties', ['id', 'description']);
+      ->addConstraint('ImmutableProperties', ['properties' => ['id', 'description']]);
 
     /** @var \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager */
     $typed_data_manager = $this->container->get(TypedDataManagerInterface::class);
diff --git a/core/tests/Drupal/KernelTests/Core/Extension/ExtensionExistsConstraintValidatorTest.php b/core/tests/Drupal/KernelTests/Core/Extension/ExtensionExistsConstraintValidatorTest.php
index 6868cd519c8cb1eed97b8aa8cb028c341d4de2bc..993debd204841d66403f755e4ee0a7c9b0a26d38 100644
--- a/core/tests/Drupal/KernelTests/Core/Extension/ExtensionExistsConstraintValidatorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Extension/ExtensionExistsConstraintValidatorTest.php
@@ -29,7 +29,7 @@ public function testValidation(): void {
     // Create a data definition that specifies the value must be a string with
     // the name of an installed module.
     $definition = DataDefinition::create('string')
-      ->addConstraint('ExtensionExists', 'module');
+      ->addConstraint('ExtensionExists', ['type' => 'module']);
 
     /** @var \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data */
     $typed_data = $this->container->get('typed_data_manager');
@@ -52,7 +52,7 @@ public function testValidation(): void {
     $data->setValue(NULL);
     $this->assertCount(0, $data->validate());
 
-    $definition->setConstraints(['ExtensionExists' => 'theme']);
+    $definition->setConstraints(['ExtensionExists' => ['type' => 'theme']]);
     $data = $typed_data->create($definition, 'stark');
 
     $violations = $data->validate();
@@ -80,7 +80,7 @@ public function testValidation(): void {
     $this->assertCount(0, $data->validate());
 
     // Anything but a module or theme should raise an exception.
-    $definition->setConstraints(['ExtensionExists' => 'profile']);
+    $definition->setConstraints(['ExtensionExists' => ['type' => 'profile']]);
     $this->expectExceptionMessage("Unknown extension type: 'profile'");
     $data->validate();
   }
diff --git a/core/tests/Drupal/KernelTests/Core/Plugin/PluginExistsConstraintValidatorTest.php b/core/tests/Drupal/KernelTests/Core/Plugin/PluginExistsConstraintValidatorTest.php
index 9b37a142ae069d8efe03dd2331ee41d6994dda95..fcde5e478c4b7f854304b3157a6f65670f7d5cb3 100644
--- a/core/tests/Drupal/KernelTests/Core/Plugin/PluginExistsConstraintValidatorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Plugin/PluginExistsConstraintValidatorTest.php
@@ -30,7 +30,7 @@ class PluginExistsConstraintValidatorTest extends KernelTestBase {
    */
   public function testValidation(): void {
     $definition = DataDefinition::create('string')
-      ->addConstraint('PluginExists', 'plugin.manager.action');
+      ->addConstraint('PluginExists', ['manager' => 'plugin.manager.action']);
 
     // An existing action plugin should pass validation.
     $data = $this->container->get('typed_data_manager')->create($definition);
diff --git a/core/tests/Drupal/KernelTests/Core/TypedData/AllowedValuesConstraintValidatorTest.php b/core/tests/Drupal/KernelTests/Core/TypedData/AllowedValuesConstraintValidatorTest.php
index acefd78cd7237541f4407a8b57dc015d70dcbe9f..625fe2a48d4a2835184ffac4503356b47847538a 100644
--- a/core/tests/Drupal/KernelTests/Core/TypedData/AllowedValuesConstraintValidatorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/TypedData/AllowedValuesConstraintValidatorTest.php
@@ -6,7 +6,6 @@
 
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\KernelTests\KernelTestBase;
-use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
 
 /**
  * Tests AllowedValues validation constraint with both valid and invalid values.
@@ -113,8 +112,8 @@ public function testValidationCallbackException(): void {
       ->addConstraint('AllowedValues', ['choices' => [1, 2, 3], 'callback' => [static::class, 'doesNotExist']]);
     $typed_data = $this->typedData->create($definition, 1);
 
-    $this->expectException(ConstraintDefinitionException::class);
-    $this->expectExceptionMessage('The AllowedValuesConstraint constraint expects a valid callback');
+    $this->expectException(\TypeError::class);
+    $this->expectExceptionMessage('Symfony\Component\Validator\Constraints\Choice::__construct(): Argument #3 ($callback) must be of type callable|string|null, array given');
     $typed_data->validate();
   }
 
diff --git a/core/tests/Drupal/KernelTests/Core/TypedData/ComplexDataConstraintValidatorTest.php b/core/tests/Drupal/KernelTests/Core/TypedData/ComplexDataConstraintValidatorTest.php
index 17934095205a8926d756af339d097f0775008bd2..0a263cb9e9359b50e90496788e63a98daa8c0e61 100644
--- a/core/tests/Drupal/KernelTests/Core/TypedData/ComplexDataConstraintValidatorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/TypedData/ComplexDataConstraintValidatorTest.php
@@ -40,8 +40,10 @@ public function testValidation(): void {
     $definition = MapDataDefinition::create()
       ->setPropertyDefinition('key', DataDefinition::create('integer'))
       ->addConstraint('ComplexData', [
-        'key' => [
-          'AllowedValues' => [1, 2, 3],
+        'properties' => [
+          'key' => [
+            'AllowedValues' => [1, 2, 3],
+          ],
         ],
       ]);
 
@@ -70,8 +72,10 @@ public function testValidation(): void {
     $definition = MapDataDefinition::create()
       ->setPropertyDefinition('key', DataDefinition::create('integer'))
       ->addConstraint('ComplexData', [
-        'key' => [
-          'NotNull' => [],
+        'properties' => [
+          'key' => [
+            'NotNull' => [],
+          ],
         ],
       ]);
 
diff --git a/core/tests/Drupal/KernelTests/Core/TypedData/ValidKeysConstraintValidatorTest.php b/core/tests/Drupal/KernelTests/Core/TypedData/ValidKeysConstraintValidatorTest.php
index 5026321001a9a491c5288462cd84027d9f434d90..80cb3abd2aa6ce0eefa39bb38361d80e06ec5e7a 100644
--- a/core/tests/Drupal/KernelTests/Core/TypedData/ValidKeysConstraintValidatorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/TypedData/ValidKeysConstraintValidatorTest.php
@@ -228,7 +228,7 @@ public function testBothUnknownAndDynamicallyRequiredKeys(bool $block_is_fully_v
   public function testValidation(): void {
     // Create a data definition that specifies certain allowed keys.
     $definition = MapDataDefinition::create('mapping')
-      ->addConstraint('ValidKeys', ['north', 'south', 'west']);
+      ->addConstraint('ValidKeys', ['allowedKeys' => ['north', 'south', 'west']]);
     $definition['mapping'] = [
       'north' => ['type' => 'string', 'requiredKey' => FALSE],
       'east' => ['type' => 'string', 'requiredKey' => FALSE],
@@ -326,7 +326,7 @@ public function testValidKeyInference(): void {
     $config = $this->container->get('config.typed')
       ->get('system.site');
     $config->getDataDefinition()
-      ->addConstraint('ValidKeys', '<infer>');
+      ->addConstraint('ValidKeys', ['allowedKeys' => '<infer>'],);
 
     $data = $config->getValue();
     $data['invalid-key'] = "There's a snake in my boots.";
@@ -338,7 +338,7 @@ public function testValidKeyInference(): void {
     // Ensure that ValidKeys will freak out if the option is not exactly
     // `<infer>`.
     $config->getDataDefinition()
-      ->addConstraint('ValidKeys', 'infer');
+      ->addConstraint('ValidKeys', ['allowedKeys' => 'infer']);
     $this->expectExceptionMessage("'infer' is not a valid set of allowed keys.");
     $config->validate();
   }
diff --git a/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php b/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php
index 6a1a14e4946917f945e11153228232f36108687d..0ad8050b28feb8297db4df610096fc400bef0809 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php
@@ -163,7 +163,7 @@ public static function providerTestIsSatisfiedBy() {
     $data['content entity, incorrect manual constraint'] = [
       TRUE,
       EntityContextDefinition::fromEntityType($content),
-      EntityContextDefinition::fromEntityType($content)->addConstraint('EntityType', 'test_config'),
+      EntityContextDefinition::fromEntityType($content)->addConstraint('EntityType', ['type' => 'test_config']),
     ];
     $data['config entity, matching type, no value'] = [
       TRUE,
@@ -235,9 +235,9 @@ public function testIsSatisfiedByGenerateBundledEntity($expected, array $require
 
     $requirement = EntityContextDefinition::fromEntityType($entity_type);
     if ($requirement_bundles) {
-      $requirement->addConstraint('Bundle', $requirement_bundles);
+      $requirement->addConstraint('Bundle', ['bundle' => $requirement_bundles]);
     }
-    $definition = EntityContextDefinition::fromEntityType($entity_type)->addConstraint('Bundle', $candidate_bundles);
+    $definition = EntityContextDefinition::fromEntityType($entity_type)->addConstraint('Bundle', ['bundle' => $candidate_bundles]);
     $this->assertRequirementIsSatisfied($expected, $requirement, $definition);
   }
 
@@ -313,7 +313,7 @@ public function testIsSatisfiedByPassBundledEntity($expected, $requirement_const
 
     $requirement = EntityContextDefinition::fromEntityTypeId('test_content');
     if ($requirement_constraint) {
-      $requirement->addConstraint('Bundle', $requirement_constraint);
+      $requirement->addConstraint('Bundle', ['bundle' => $requirement_constraint]);
     }
     $definition = EntityContextDefinition::fromEntityTypeId('test_content');
     $this->assertRequirementIsSatisfied($expected, $requirement, $definition, $entity->reveal());