diff --git a/core/lib/Drupal/Core/TypedData/TypedDataManager.php b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
index aab5850ada178d044a4a1bff339947c2dad1c8d4..eb70e0e3c9cd6cf753670d5f7d6f9f5fe23bcbf0 100644
--- a/core/lib/Drupal/Core/TypedData/TypedDataManager.php
+++ b/core/lib/Drupal/Core/TypedData/TypedDataManager.php
@@ -8,11 +8,11 @@
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
-use Drupal\Core\TypedData\Validation\ExecutionContextFactory;
 use Drupal\Core\TypedData\Validation\RecursiveValidator;
 use Drupal\Core\Validation\ConstraintManager;
 use Drupal\Core\Validation\ConstraintValidatorFactory;
 use Drupal\Core\Validation\DrupalTranslator;
+use Drupal\Core\Validation\ExecutionContextFactory;
 use Symfony\Component\Validator\Validator\ValidatorInterface;
 
 /**
diff --git a/core/lib/Drupal/Core/TypedData/Validation/ConstraintViolationBuilder.php b/core/lib/Drupal/Core/TypedData/Validation/ConstraintViolationBuilder.php
index f2fe2f378ff8613b52621a9815213e90a9b518ea..1bef1036bc4f6350659616e58f9fe91a977250a5 100644
--- a/core/lib/Drupal/Core/TypedData/Validation/ConstraintViolationBuilder.php
+++ b/core/lib/Drupal/Core/TypedData/Validation/ConstraintViolationBuilder.php
@@ -5,12 +5,10 @@
 // phpcs:ignoreFile Portions of this file are a direct copy of
 // \Symfony\Component\Validator\Violation\ConstraintViolationBuilder.
 
+use Drupal\Core\Validation\ConstraintViolationBuilder as NewConstraintViolationBuilder;
 use Drupal\Core\Validation\TranslatorInterface;
 use Symfony\Component\Validator\Constraint;
-use Symfony\Component\Validator\ConstraintViolation;
 use Symfony\Component\Validator\ConstraintViolationList;
-use Symfony\Component\Validator\Util\PropertyPath;
-use Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface;
 
 /**
  * Defines a constraint violation builder for the Typed Data validator.
@@ -18,84 +16,7 @@
  * We do not use the builder provided by Symfony as it is marked internal.
  *
  */
-class ConstraintViolationBuilder implements ConstraintViolationBuilderInterface {
-
-  /**
-   * The list of violations.
-   *
-   * @var \Symfony\Component\Validator\ConstraintViolationList
-   */
-  protected $violations;
-
-  /**
-   * The violation message.
-   *
-   * @var string
-   */
-  protected $message;
-
-  /**
-   * The message parameters.
-   *
-   * @var array
-   */
-  protected $parameters;
-
-  /**
-   * The root path.
-   *
-   * @var mixed
-   */
-  protected $root;
-
-  /**
-   * The invalid value caused the violation.
-   *
-   * @var mixed
-   */
-  protected $invalidValue;
-
-  /**
-   * The property path.
-   *
-   * @var string
-   */
-  protected $propertyPath;
-
-  /**
-   * The translator.
-   *
-   * @var \Drupal\Core\Validation\TranslatorInterface
-   */
-  protected $translator;
-
-  /**
-   * The translation domain.
-   *
-   * @var string|false|null
-   */
-  protected $translationDomain;
-
-  /**
-   * The number used
-   * @var int|null
-   */
-  protected $plural;
-
-  /**
-   * @var Constraint
-   */
-  protected $constraint;
-
-  /**
-   * @var mixed
-   */
-  protected $code;
-
-  /**
-   * @var mixed
-   */
-  protected $cause;
+class ConstraintViolationBuilder extends NewConstraintViolationBuilder {
 
   /**
    * Constructs a new ConstraintViolationBuilder instance.
@@ -119,149 +40,9 @@ class ConstraintViolationBuilder implements ConstraintViolationBuilderInterface
    * @param null $translationDomain
    *   (optional) The translation domain.
    */
-  public function __construct(ConstraintViolationList $violations, Constraint $constraint, $message, array $parameters, $root, $propertyPath, $invalidValue, TranslatorInterface $translator, $translationDomain = null)
-    {
-      $this->violations = $violations;
-      $this->message = $message;
-      $this->parameters = $parameters;
-      $this->root = $root;
-      $this->propertyPath = $propertyPath;
-      $this->invalidValue = $invalidValue;
-      $this->translator = $translator;
-      $this->translationDomain = $translationDomain;
-      $this->constraint = $constraint;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function atPath($path): static
-    {
-      $this->propertyPath = PropertyPath::append($this->propertyPath, $path);
-
-      return $this;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function setParameter($key, $value): static
-    {
-      $this->parameters[$key] = $value;
-
-      return $this;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function setParameters(array $parameters): static
-    {
-      $this->parameters = $parameters;
-
-      return $this;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function setTranslationDomain($translationDomain): static
-    {
-      $this->translationDomain = $translationDomain;
-
-      return $this;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function setInvalidValue($invalidValue): static
-    {
-      $this->invalidValue = $invalidValue;
-
-      return $this;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function setPlural($number): static
-    {
-      $this->plural = $number;
-
-      return $this;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function setCode($code): static
-    {
-      $this->code = $code;
-
-      return $this;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function setCause($cause): static
-    {
-      $this->cause = $cause;
-
-      return $this;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function addViolation(): void
-    {
-      if (null === $this->plural) {
-        $translatedMessage = $this->translator->trans(
-          $this->message,
-          $this->parameters,
-          $this->translationDomain
-        );
-      } else {
-        try {
-          $translatedMessage = $this->translator->transChoice(
-            $this->message,
-            $this->plural,
-            $this->parameters,
-            $this->translationDomain#
-          );
-        } catch (\InvalidArgumentException $e) {
-          $translatedMessage = $this->translator->trans(
-            $this->message,
-            $this->parameters,
-            $this->translationDomain
-          );
-        }
-      }
-
-      $this->violations->add(new ConstraintViolation(
-        $translatedMessage,
-        $this->message,
-        $this->parameters,
-        $this->root,
-        $this->propertyPath,
-        $this->invalidValue,
-        $this->plural,
-        $this->code,
-        $this->constraint,
-        $this->cause
-      ));
-    }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function disableTranslation(): static
-  {
-    $this->translationDomain = false;
-
-    return $this;
+  public function __construct(ConstraintViolationList $violations, Constraint $constraint, $message, array $parameters, $root, $propertyPath, $invalidValue, TranslatorInterface $translator, $translationDomain = null)   {
+    @trigger_error(__CLASS__ . ' is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Instead, use \Drupal\Core\Validation\ConstraintViolationBuilder. See https://www.drupal.org/node/3396238', E_USER_DEPRECATED);
+    parent::__construct($violations, $constraint, $message, $parameters, $root, $propertyPath, $invalidValue, $translator, $translationDomain);
   }
 
 }
diff --git a/core/lib/Drupal/Core/TypedData/Validation/ExecutionContext.php b/core/lib/Drupal/Core/TypedData/Validation/ExecutionContext.php
index 7c35260b21670c324cbde5b6aa1756c68d9398db..c2f4142b5844e467d33b04faf5f7001b20f35400 100644
--- a/core/lib/Drupal/Core/TypedData/Validation/ExecutionContext.php
+++ b/core/lib/Drupal/Core/TypedData/Validation/ExecutionContext.php
@@ -2,15 +2,8 @@
 
 namespace Drupal\Core\TypedData\Validation;
 
+use Drupal\Core\Validation\ExecutionContext as NewExecutionContext;
 use Drupal\Core\Validation\TranslatorInterface;
-use Symfony\Component\Validator\Constraint;
-use Symfony\Component\Validator\ConstraintViolation;
-use Symfony\Component\Validator\ConstraintViolationList;
-use Symfony\Component\Validator\ConstraintViolationListInterface;
-use Symfony\Component\Validator\Context\ExecutionContextInterface;
-use Symfony\Component\Validator\Mapping\MetadataInterface;
-use Symfony\Component\Validator\Util\PropertyPath;
-use Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface;
 use Symfony\Component\Validator\Validator\ValidatorInterface;
 
 /**
@@ -20,92 +13,7 @@
  * this class is pretty much the same, but has some code style changes as well
  * as exceptions for methods we don't support.
  */
-class ExecutionContext implements ExecutionContextInterface {
-
-  /**
-   * @var \Symfony\Component\Validator\Validator\ValidatorInterface
-   */
-  protected $validator;
-
-  /**
-   * The root value of the validated object graph.
-   *
-   * @var mixed
-   */
-  protected $root;
-
-  /**
-   * @var \Drupal\Core\Validation\TranslatorInterface
-   */
-  protected $translator;
-
-  /**
-   * @var string
-   */
-  protected $translationDomain;
-
-  /**
-   * The violations generated in the current context.
-   *
-   * @var \Symfony\Component\Validator\ConstraintViolationList
-   */
-  protected $violations;
-
-  /**
-   * The currently validated value.
-   *
-   * @var mixed
-   */
-  protected $value;
-
-  /**
-   * The currently validated typed data object.
-   *
-   * @var \Drupal\Core\TypedData\TypedDataInterface
-   */
-  protected $data;
-
-  /**
-   * The property path leading to the current value.
-   *
-   * @var string
-   */
-  protected $propertyPath = '';
-
-  /**
-   * The current validation metadata.
-   *
-   * @var \Symfony\Component\Validator\Mapping\MetadataInterface|null
-   */
-  protected $metadata;
-
-  /**
-   * The currently validated group.
-   *
-   * @var string|null
-   */
-  protected $group;
-
-  /**
-   * The currently validated constraint.
-   *
-   * @var \Symfony\Component\Validator\Constraint|null
-   */
-  protected $constraint;
-
-  /**
-   * Stores which objects have been validated in which group.
-   *
-   * @var array
-   */
-  protected $validatedObjects = [];
-
-  /**
-   * Stores which class constraint has been validated for which object.
-   *
-   * @var array
-   */
-  protected $validatedConstraints = [];
+class ExecutionContext extends NewExecutionContext {
 
   /**
    * Creates a new ExecutionContext.
@@ -119,165 +27,12 @@ class ExecutionContext implements ExecutionContextInterface {
    * @param string $translationDomain
    *   (optional) The translation domain.
    *
-   * @internal Called by \Drupal\Core\TypedData\Validation\ExecutionContextFactory.
+   * @internal Called by \Drupal\Core\Validation\ExecutionContextFactory.
    *    Should not be used in user code.
    */
   public function __construct(ValidatorInterface $validator, $root, TranslatorInterface $translator, $translationDomain = NULL) {
-    $this->validator = $validator;
-    $this->root = $root;
-    $this->translator = $translator;
-    $this->translationDomain = $translationDomain;
-    $this->violations = new ConstraintViolationList();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setNode($value, $object, MetadataInterface $metadata = NULL, $propertyPath): void {
-    $this->value = $value;
-    $this->data = $object;
-    $this->metadata = $metadata;
-    $this->propertyPath = (string) $propertyPath;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setGroup($group): void {
-    $this->group = $group;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setConstraint(Constraint $constraint): void {
-    $this->constraint = $constraint;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function addViolation($message, array $parameters = []): void {
-    $this->violations->add(new ConstraintViolation($this->translator->trans($message, $parameters, $this->translationDomain), $message, $parameters, $this->root, $this->propertyPath, $this->value, NULL, NULL, $this->constraint));
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildViolation($message, array $parameters = []): ConstraintViolationBuilderInterface {
-    return new ConstraintViolationBuilder($this->violations, $this->constraint, $message, $parameters, $this->root, $this->propertyPath, $this->value, $this->translator, $this->translationDomain);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getViolations(): ConstraintViolationListInterface {
-    return $this->violations;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getValidator(): ValidatorInterface {
-    return $this->validator;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getRoot(): mixed {
-    return $this->root;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getValue(): mixed {
-    return $this->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getObject(): ?object {
-    return $this->data;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getMetadata(): ?MetadataInterface {
-    return $this->metadata;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getGroup(): ?string {
-    return Constraint::DEFAULT_GROUP;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getClassName(): ?string {
-    return get_class($this->data);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getPropertyName(): ?string {
-    return $this->data->getName();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getPropertyPath($sub_path = ''): string {
-    return PropertyPath::append($this->propertyPath, $sub_path);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function markConstraintAsValidated($cache_key, $constraint_hash): void {
-    $this->validatedConstraints[$cache_key . ':' . $constraint_hash] = TRUE;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function isConstraintValidated($cache_key, $constraint_hash): bool {
-    return isset($this->validatedConstraints[$cache_key . ':' . $constraint_hash]);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function markGroupAsValidated($cache_key, $group_hash): void {
-    $this->validatedObjects[$cache_key][$group_hash] = TRUE;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function isGroupValidated($cache_key, $group_hash): bool {
-    return isset($this->validatedObjects[$cache_key][$group_hash]);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function markObjectAsInitialized($cache_key): void {
-    throw new \LogicException('\Symfony\Component\Validator\Context\ExecutionContextInterface::markObjectAsInitialized is unsupported.');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function isObjectInitialized($cache_key): bool {
-    throw new \LogicException('\Symfony\Component\Validator\Context\ExecutionContextInterface::isObjectInitialized is unsupported.');
+    @trigger_error(__CLASS__ . ' is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Instead, use \Drupal\Core\Validation\ExecutionContext. See https://www.drupal.org/node/3396238', E_USER_DEPRECATED);
+    parent::__construct($validator, $root, $translator, $translationDomain);
   }
 
 }
diff --git a/core/lib/Drupal/Core/TypedData/Validation/ExecutionContextFactory.php b/core/lib/Drupal/Core/TypedData/Validation/ExecutionContextFactory.php
index 5c6a8264cd9c25fc53b04f2073414a05301e2229..63bc0b8e49a0659845cc73f508a348125788af45 100644
--- a/core/lib/Drupal/Core/TypedData/Validation/ExecutionContextFactory.php
+++ b/core/lib/Drupal/Core/TypedData/Validation/ExecutionContextFactory.php
@@ -2,27 +2,15 @@
 
 namespace Drupal\Core\TypedData\Validation;
 
+use Drupal\Core\Validation\ExecutionContextFactory as NewExecutionContextFactory;
 use Drupal\Core\Validation\TranslatorInterface;
-use Symfony\Component\Validator\Context\ExecutionContextFactoryInterface;
-use Symfony\Component\Validator\Context\ExecutionContextInterface;
-use Symfony\Component\Validator\Validator\ValidatorInterface;
 
 /**
  * Defines an execution factory for the Typed Data validator.
  *
  * We do not use the factory provided by Symfony as it is marked internal.
  */
-class ExecutionContextFactory implements ExecutionContextFactoryInterface {
-
-  /**
-   * @var \Drupal\Core\Validation\TranslatorInterface
-   */
-  protected $translator;
-
-  /**
-   * @var string|null
-   */
-  protected $translationDomain;
+class ExecutionContextFactory extends NewExecutionContextFactory {
 
   /**
    * Constructs a new ExecutionContextFactory instance.
@@ -33,20 +21,8 @@ class ExecutionContextFactory implements ExecutionContextFactoryInterface {
    *   (optional) The translation domain.
    */
   public function __construct(TranslatorInterface $translator, $translationDomain = NULL) {
-    $this->translator = $translator;
-    $this->translationDomain = $translationDomain;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function createContext(ValidatorInterface $validator, $root): ExecutionContextInterface {
-    return new ExecutionContext(
-      $validator,
-      $root,
-      $this->translator,
-      $this->translationDomain
-    );
+    @trigger_error(__CLASS__ . ' is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Instead, use \Drupal\Core\Validation\ExecutionContextFactory. See https://www.drupal.org/node/3396238', E_USER_DEPRECATED);
+    parent::__construct($translator, $translationDomain);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Validation/BasicRecursiveValidatorFactory.php b/core/lib/Drupal/Core/Validation/BasicRecursiveValidatorFactory.php
index 6540f4f9e4ad475a50b47b4cce85f85e4e82b904..5ce93b6bd13d37b385f31af013bd0daad835f640 100644
--- a/core/lib/Drupal/Core/Validation/BasicRecursiveValidatorFactory.php
+++ b/core/lib/Drupal/Core/Validation/BasicRecursiveValidatorFactory.php
@@ -5,7 +5,6 @@
 namespace Drupal\Core\Validation;
 
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
-use Drupal\Core\TypedData\Validation\ExecutionContextFactory;
 use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory;
 use Symfony\Component\Validator\Validator\RecursiveValidator;
 
diff --git a/core/lib/Drupal/Core/Validation/ConstraintViolationBuilder.php b/core/lib/Drupal/Core/Validation/ConstraintViolationBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..b4eeef3724357d1cb47062a90c9d60969a1ef880
--- /dev/null
+++ b/core/lib/Drupal/Core/Validation/ConstraintViolationBuilder.php
@@ -0,0 +1,198 @@
+<?php
+
+namespace Drupal\Core\Validation;
+
+// phpcs:ignoreFile Portions of this file are a direct copy of
+// \Symfony\Component\Validator\Violation\ConstraintViolationBuilder.
+
+use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Validator\ConstraintViolation;
+use Symfony\Component\Validator\ConstraintViolationList;
+use Symfony\Component\Validator\Util\PropertyPath;
+use Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface;
+
+/**
+ * A constraint violation builder for the basic Symfony validator.
+ *
+ * We do not use the builder provided by Symfony as it is marked internal.
+ *
+ */
+class ConstraintViolationBuilder implements ConstraintViolationBuilderInterface {
+
+  /**
+   * The number used
+   */
+  protected ?int $plural = NULL;
+
+  /**
+   * The code.
+   */
+  protected mixed $code = NULL;
+
+  /**
+   * The cause.
+   */
+  protected mixed $cause = NULL;
+
+  /**
+   * Constructs a new ConstraintViolationBuilder instance.
+   *
+   * @param \Symfony\Component\Validator\ConstraintViolationList $violations
+   *   The violation list.
+   * @param \Symfony\Component\Validator\Constraint $constraint
+   *   The constraint.
+   * @param string $message
+   *   The message.
+   * @param array $parameters
+   *   The message parameters.
+   * @param mixed $root
+   *   The root.
+   * @param string $propertyPath
+   *   The property string.
+   * @param mixed $invalidValue
+   *   The invalid value.
+   * @param \Drupal\Core\Validation\TranslatorInterface $translator
+   *   The translator.
+   * @param string|false|null $translationDomain
+   *   (optional) The translation domain.
+   */
+  public function __construct(
+    protected ConstraintViolationList $violations,
+    protected Constraint $constraint,
+    protected string $message,
+    protected array $parameters,
+    protected mixed $root,
+    protected string $propertyPath,
+    protected mixed $invalidValue,
+    protected TranslatorInterface $translator,
+    protected string | false | null $translationDomain = NULL
+  ) {}
+
+  /**
+   * {@inheritdoc}
+   */
+  public function atPath(mixed $path): static {
+    if (!is_string($path)) {
+      @\trigger_error('Passing the $path parameter as a non-string value to ' . __METHOD__ . '() is deprecated in drupal:10.3.0 and will be required in drupal:11.0.0. See https://www.drupal.org/node/3396238', E_USER_DEPRECATED);
+    }
+    $this->propertyPath = PropertyPath::append($this->propertyPath, (string) $path);
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setParameter(string $key, mixed $value): static {
+    $this->parameters[$key] = $value;
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setParameters(array $parameters): static {
+    $this->parameters = $parameters;
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setTranslationDomain(string $translationDomain): static {
+    $this->translationDomain = $translationDomain;
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setInvalidValue(mixed $invalidValue): static {
+    $this->invalidValue = $invalidValue;
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setPlural(int $number): static {
+    $this->plural = $number;
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setCode(?string $code): static {
+    $this->code = $code;
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setCause(mixed $cause): static {
+    $this->cause = $cause;
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addViolation(): void {
+    if (NULL === $this->plural) {
+      $translatedMessage = $this->translator->trans(
+        $this->message,
+        $this->parameters,
+        $this->translationDomain
+      );
+    }
+    else {
+      try {
+        $translatedMessage = $this->translator->transChoice(
+          $this->message,
+          $this->plural,
+          $this->parameters,
+          $this->translationDomain#
+        );
+      }
+      catch (\InvalidArgumentException $e) {
+        $translatedMessage = $this->translator->trans(
+          $this->message,
+          $this->parameters,
+          $this->translationDomain
+        );
+      }
+    }
+
+    $this->violations->add(new ConstraintViolation(
+      $translatedMessage,
+      $this->message,
+      $this->parameters,
+      $this->root,
+      $this->propertyPath,
+      $this->invalidValue,
+      $this->plural,
+      $this->code,
+      $this->constraint,
+      $this->cause
+    ));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function disableTranslation(): static {
+    $this->translationDomain = FALSE;
+
+    return $this;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Validation/ExecutionContext.php b/core/lib/Drupal/Core/Validation/ExecutionContext.php
new file mode 100644
index 0000000000000000000000000000000000000000..ad732ea9f92768bc56bcbbf33deb66c33c4f6940
--- /dev/null
+++ b/core/lib/Drupal/Core/Validation/ExecutionContext.php
@@ -0,0 +1,244 @@
+<?php
+
+namespace Drupal\Core\Validation;
+
+use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Validator\ConstraintViolation;
+use Symfony\Component\Validator\ConstraintViolationList;
+use Symfony\Component\Validator\ConstraintViolationListInterface;
+use Symfony\Component\Validator\Context\ExecutionContextInterface;
+use Symfony\Component\Validator\Mapping\MetadataInterface;
+use Symfony\Component\Validator\Mapping\PropertyMetadataInterface;
+use Symfony\Component\Validator\Util\PropertyPath;
+use Symfony\Component\Validator\Validator\ValidatorInterface;
+use Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface;
+
+/**
+ * Defines an execution context class.
+ *
+ * We do not use the context provided by Symfony as it is marked internal, so
+ * this class is pretty much the same, but has some code style changes as well
+ * as exceptions for methods we don't support.
+ */
+class ExecutionContext implements ExecutionContextInterface {
+
+  /**
+   * The violations generated in the current context.
+   */
+  protected ConstraintViolationList $violations;
+
+  /**
+   * The currently validated value.
+   */
+  protected mixed $value = NULL;
+
+  /**
+   * The currently validated object.
+   */
+  protected ?object $object = NULL;
+
+  /**
+   * The property path leading to the current value.
+   */
+  protected string $propertyPath = '';
+
+  /**
+   * The current validation metadata.
+   */
+  protected ?MetadataInterface $metadata = NULL;
+
+  /**
+   * The currently validated group.
+   */
+  protected ?string $group;
+
+  /**
+   * The currently validated constraint.
+   */
+  protected ?Constraint $constraint;
+
+  /**
+   * Stores which objects have been validated in which group.
+   */
+  protected array $validatedObjects = [];
+
+  /**
+   * Stores which class constraint has been validated for which object.
+   */
+  protected array $validatedConstraints = [];
+
+  /**
+   * Creates a new ExecutionContext.
+   *
+   * @param \Symfony\Component\Validator\Validator\ValidatorInterface $validator
+   *   The validator.
+   * @param mixed $root
+   *   The root.
+   * @param \Drupal\Core\Validation\TranslatorInterface $translator
+   *   The translator.
+   * @param string|null $translationDomain
+   *   (optional) The translation domain.
+   *
+   * @internal Called by \Drupal\Core\Validation\ExecutionContextFactory.
+   *    Should not be used in user code.
+   */
+  public function __construct(
+    protected ValidatorInterface $validator,
+    protected mixed $root,
+    protected TranslatorInterface $translator,
+    protected ?string $translationDomain = NULL
+  ) {
+    $this->violations = new ConstraintViolationList();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setNode(mixed $value, ?object $object, ?MetadataInterface $metadata, string $propertyPath): void {
+    $this->value = $value;
+    $this->object = $object;
+    $this->metadata = $metadata;
+    $this->propertyPath = $propertyPath;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setConstraint(Constraint $constraint): void {
+    $this->constraint = $constraint;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addViolation(string $message, array $params = []): void {
+    $this->violations->add(new ConstraintViolation($this->translator->trans($message, $params, $this->translationDomain), $message, $params, $this->root, $this->propertyPath, $this->value, NULL, NULL, $this->constraint));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildViolation(string $message, array $parameters = []): ConstraintViolationBuilderInterface {
+    return new ConstraintViolationBuilder($this->violations, $this->constraint, $message, $parameters, $this->root, $this->propertyPath, $this->value, $this->translator, $this->translationDomain);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getViolations(): ConstraintViolationListInterface {
+    return $this->violations;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValidator(): ValidatorInterface {
+    return $this->validator;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRoot(): mixed {
+    return $this->root;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue(): mixed {
+    return $this->value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getObject(): ?object {
+    return $this->object;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMetadata(): ?MetadataInterface {
+    return $this->metadata;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGroup(): ?string {
+    return Constraint::DEFAULT_GROUP;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setGroup(?string $group): void {
+    $this->group = $group;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getClassName(): ?string {
+    return get_class($this->object);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPropertyName(): ?string {
+    return $this->metadata instanceof PropertyMetadataInterface ? $this->metadata->getPropertyName() : NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPropertyPath(string $subPath = ''): string {
+    return PropertyPath::append($this->propertyPath, $subPath);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function markConstraintAsValidated(string $cacheKey, string $constraintHash): void {
+    $this->validatedConstraints[$cacheKey . ':' . $constraintHash] = TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isConstraintValidated(string $cacheKey, string $constraintHash): bool {
+    return isset($this->validatedConstraints[$cacheKey . ':' . $constraintHash]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function markGroupAsValidated(string $cacheKey, string $groupHash): void {
+    $this->validatedObjects[$cacheKey][$groupHash] = TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isGroupValidated(string $cacheKey, string $groupHash): bool {
+    return isset($this->validatedObjects[$cacheKey][$groupHash]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function markObjectAsInitialized(string $cacheKey): void {
+    throw new \LogicException(ExecutionContextInterface::class . '::markObjectAsInitialized is unsupported.');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isObjectInitialized(string $cacheKey): bool {
+    throw new \LogicException(ExecutionContextInterface::class . '::isObjectInitialized is unsupported.');
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Validation/ExecutionContextFactory.php b/core/lib/Drupal/Core/Validation/ExecutionContextFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..a32873430c6bcda1aadbfe7af0e42937167ab523
--- /dev/null
+++ b/core/lib/Drupal/Core/Validation/ExecutionContextFactory.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Drupal\Core\Validation;
+
+use Symfony\Component\Validator\Context\ExecutionContextFactoryInterface;
+use Symfony\Component\Validator\Context\ExecutionContextInterface;
+use Symfony\Component\Validator\Validator\ValidatorInterface;
+
+/**
+ * Defines an execution factory for the Symfony validator.
+ *
+ * We do not use the factory provided by Symfony as it is marked internal.
+ */
+class ExecutionContextFactory implements ExecutionContextFactoryInterface {
+
+  /**
+   * Constructs a new ExecutionContextFactory instance.
+   *
+   * @param \Drupal\Core\Validation\TranslatorInterface $translator
+   *   The translator instance.
+   * @param string|null $translationDomain
+   *   (optional) The translation domain.
+   */
+  public function __construct(
+    protected TranslatorInterface $translator,
+    protected ?string $translationDomain = NULL) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createContext(ValidatorInterface $validator, mixed $root): ExecutionContextInterface {
+    return new ExecutionContext(
+      $validator,
+      $root,
+      $this->translator,
+      $this->translationDomain
+    );
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php
index 050f108d69ea4a1f75e0f02a0acac805745575e5..3326fdf32589562920a150f681d315cd2dfb95b6 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php
@@ -91,7 +91,7 @@ public function validate($items, Constraint $constraint) {
           ->setParameter('@field_name', $field_label)
           ->setParameter('%value', $dupe);
         if ($is_multiple) {
-          $violation->atPath($delta);
+          $violation->atPath((string) $delta);
         }
         $violation->addViolation();
       }
@@ -106,7 +106,7 @@ public function validate($items, Constraint $constraint) {
           ->setParameter('@entity_type', $entity_label)
           ->setParameter('@field_name', $field_label)
           ->setParameter('%value', $dupe)
-          ->atPath($delta)
+          ->atPath((string) $delta)
           ->addViolation();
       }
     }
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ValidKeysConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ValidKeysConstraintValidator.php
index d30ed9c42c7cd27e21f411847deaf64dc2d6f0fa..5fa43468985aaeafff96372eacc2333545debc7c 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ValidKeysConstraintValidator.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/ValidKeysConstraintValidator.php
@@ -58,7 +58,7 @@ public function validate(mixed $value, Constraint $constraint) {
     foreach ($invalid_keys as $key) {
       $this->context->buildViolation($constraint->invalidKeyMessage)
         ->setParameter('@key', $key)
-        ->atPath($key)
+        ->atPath((string) $key)
         ->setInvalidValue($key)
         ->addViolation();
     }
diff --git a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/PrecedingConstraintAwareValidatorTrait.php b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/PrecedingConstraintAwareValidatorTrait.php
index 0e6ae75076cc7619051d56998a0bc8489bdcacb2..9d3494741a8902d77731fb6fc3d357d757354d73 100644
--- a/core/modules/ckeditor5/src/Plugin/Validation/Constraint/PrecedingConstraintAwareValidatorTrait.php
+++ b/core/modules/ckeditor5/src/Plugin/Validation/Constraint/PrecedingConstraintAwareValidatorTrait.php
@@ -4,7 +4,7 @@
 
 namespace Drupal\ckeditor5\Plugin\Validation\Constraint;
 
-use Drupal\Core\TypedData\Validation\ExecutionContext;
+use Drupal\Core\Validation\ExecutionContext;
 use Symfony\Component\Validator\Constraint;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
diff --git a/core/modules/file/src/Validation/RecursiveValidatorFactory.php b/core/modules/file/src/Validation/RecursiveValidatorFactory.php
index 1584a99e23869dd594324479fd462e43725f6df1..ef614afd806a905c15e0c48b72083c3c590ebcba 100644
--- a/core/modules/file/src/Validation/RecursiveValidatorFactory.php
+++ b/core/modules/file/src/Validation/RecursiveValidatorFactory.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
 use Drupal\Core\TypedData\TypedDataManagerInterface;
-use Drupal\Core\TypedData\Validation\ExecutionContextFactory;
+use Drupal\Core\Validation\ExecutionContextFactory;
 use Drupal\Core\TypedData\Validation\RecursiveValidator;
 use Drupal\Core\Validation\ConstraintValidatorFactory;
 use Drupal\Core\Validation\DrupalTranslator;
diff --git a/core/tests/Drupal/Tests/Core/TypedData/RecursiveContextualValidatorTest.php b/core/tests/Drupal/Tests/Core/TypedData/RecursiveContextualValidatorTest.php
index 46c8bd8b8eb21a4b438537c5a3777aaea15c78a2..0d940f5548e3dbdb75e0622ced06e6a8be13ddfb 100644
--- a/core/tests/Drupal/Tests/Core/TypedData/RecursiveContextualValidatorTest.php
+++ b/core/tests/Drupal/Tests/Core/TypedData/RecursiveContextualValidatorTest.php
@@ -9,9 +9,9 @@
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\Core\TypedData\MapDataDefinition;
 use Drupal\Core\TypedData\TypedDataManager;
-use Drupal\Core\TypedData\Validation\ExecutionContextFactory;
 use Drupal\Core\TypedData\Validation\RecursiveValidator;
 use Drupal\Core\Validation\ConstraintManager;
+use Drupal\Core\Validation\ExecutionContextFactory;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\Validator\ConstraintValidatorFactory;
 use Symfony\Component\Validator\Context\ExecutionContextInterface;
@@ -46,7 +46,7 @@ class RecursiveContextualValidatorTest extends UnitTestCase {
   /**
    * The execution context factory.
    *
-   * @var \Drupal\Core\TypedData\Validation\ExecutionContextFactory
+   * @var \Drupal\Core\Validation\ExecutionContextFactory
    */
   protected $contextFactory;