diff --git a/core/core.services.yml b/core/core.services.yml
index 49b27089b5..dd872eee0c 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -339,7 +339,10 @@ services:
       - [setValidationConstraintManager, ['@validation.constraint']]
   context.handler:
     class: Drupal\Core\Plugin\Context\ContextHandler
-    arguments: ['@typed_data_manager']
+    arguments: ['@context.constraint.handler']
+  context.constraint.handler:
+    class: Drupal\Core\Plugin\Context\ContextConstraintHandler
+    arguments: ['@typed_data_manager', '@entity_type.manager', '@entity_type.bundle.info']
   context.repository:
     class: Drupal\Core\Plugin\Context\LazyContextRepository
     arguments: ['@service_container']
diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextConstraintHandler.php b/core/lib/Drupal/Core/Plugin/Context/ContextConstraintHandler.php
new file mode 100644
index 0000000000..bccf36bd16
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/Context/ContextConstraintHandler.php
@@ -0,0 +1,129 @@
+<?php
+
+
+namespace Drupal\Core\Plugin\Context;
+
+
+use Drupal\Core\Entity\ContentEntityStorageInterface;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\Plugin\DataType\EntityAdapter;
+use Drupal\Core\Entity\Plugin\Validation\Constraint\BundleConstraint;
+use Drupal\Core\Entity\Plugin\Validation\Constraint\EntityTypeConstraint;
+use Drupal\Core\Entity\TypedData\EntityDataDefinition;
+use Drupal\Core\TypedData\TypedDataManagerInterface;
+
+/**
+ * Handles the constraint comparison process between contexts and definitions.
+ */
+class ContextConstraintHandler implements ContextConstraintHandlerInterface {
+
+  /**
+   * The typed data manager.
+   *
+   * @var \Drupal\Core\TypedData\TypedDataManagerInterface
+   */
+  protected $typedDataManager;
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The entity type bundle information object.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
+   */
+  protected $entityTypeBundleInfo;
+
+  /**
+   * ContextHandler constructor.
+   *
+   * @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
+   *   The typed data manager.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
+   *   The entity type bundle information object.
+   */
+  public function __construct(TypedDataManagerInterface $typed_data_manager, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
+    $this->typedDataManager = $typed_data_manager;
+    $this->entityTypeManager = $entity_type_manager;
+    $this->entityTypeBundleInfo = $entity_type_bundle_info;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateDefinitionConstraints(ContextDefinitionInterface $requirement, ContextDefinitionInterface $context_definition) {
+    $typed_data_definition = $this->getTypedDataFromContextDefinition($context_definition);
+    $validator = $this->typedDataManager->getValidator();
+    $violations = $validator->validate($typed_data_definition, array_values($this->getConstraintsFromContextDefinition($requirement)));
+    // Contexts without any violations are valid.
+    return !$violations->count();
+  }
+
+  /**
+   * Extracts an array of constraints for a context definition object.
+   *
+   * @param \Drupal\Core\Plugin\Context\ContextDefinitionInterface $definition
+   *   The context definition object.
+   *
+   * @return \Symfony\Component\Validator\Constraint[]
+   *   A list of applied constraints for the context definition.
+   */
+  protected function getConstraintsFromContextDefinition(ContextDefinitionInterface $definition) {
+    $constraints = [];
+    // If the data type is an entity, but doesn't provide a corresponding
+    // constraint, we need to manually add one to the constraints array.
+    if (strpos($definition->getDataType(), 'entity:') === 0 && !in_array('EntityType', array_keys($definition->getConstraints()))) {
+      $entity_type = substr($definition->getDataType(), 7);
+      $constraints['EntityType'] = $this->typedDataManager->getValidationConstraintManager()->create('EntityType', ['type' => $entity_type]);
+    }
+    foreach ($definition->getConstraints() as $constraint_name => $constraint_settings) {
+      $constraints[$constraint_name] = $this->typedDataManager->getValidationConstraintManager()->create($constraint_name, $constraint_settings);
+    }
+    return $constraints;
+  }
+
+  /**
+   * Provides a reliable TypedData object from a context or its definition.
+   *
+   * @param \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context_definition
+   *   The context definition from which to generate a TypedData object.
+   *
+   * @return \Drupal\Core\TypedData\TypedDataInterface The generated typed data object.
+   * The generated typed data object.
+   */
+  protected function getTypedDataFromContextDefinition(ContextDefinitionInterface $context_definition) {
+    // If the context definition has a value, just return that.
+    if ($value = $context_definition->getDefaultValue()) {
+      return $value;
+    }
+    // Get the constraints from the context's definition.
+    $constraints = $this->getConstraintsFromContextDefinition($context_definition);
+    // If constraints include EntityType, we generate an entity or adapter.
+    if (!empty($constraints['EntityType']) && $constraints['EntityType'] instanceof EntityTypeConstraint) {
+      $entity_type_id = $constraints['EntityType']->type;
+      $storage = $this->entityTypeManager->getStorage($entity_type_id);
+      // If the storage can generate a sample entity we might delegate to that.
+      if ($storage instanceof ContentEntityStorageInterface) {
+        if (!empty($constraints['Bundle']) && $constraints['Bundle'] instanceof BundleConstraint) {
+          $bundle = $constraints['Bundle']->bundle[0];
+          // We have a bundle, we are bundleable and we can generate a sample.
+          return EntityAdapter::createFromEntity($storage->createWithSampleValues($bundle));
+        }
+      }
+      // Either no bundle, or not bundleable, so generate an entity adapter.
+      $definition = EntityDataDefinition::create()
+        ->setEntityTypeId($entity_type_id);
+      return new EntityAdapter($definition);
+    }
+    // No entity related constraints, so generate a basic typed data object.
+    return $this->typedDataManager->createInstance($context_definition->getDataType());
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextConstraintHandlerInterface.php b/core/lib/Drupal/Core/Plugin/Context/ContextConstraintHandlerInterface.php
new file mode 100644
index 0000000000..1b9a189429
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/Context/ContextConstraintHandlerInterface.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Drupal\Core\Plugin\Context;
+
+/**
+ * An interface for handling context definition constraint validation.
+ */
+interface ContextConstraintHandlerInterface {
+
+  /**
+   * Validates a context definition's constraints against a context.
+   *
+   * @param \Drupal\Core\Plugin\Context\ContextDefinitionInterface $requirement
+   *   The context definition.
+   * @param \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context_definition
+   *
+   * @return bool
+   * @internal param \Drupal\Core\Plugin\Context\ContextInterface $context The context object.*   The context object.
+   */
+  public function validateDefinitionConstraints(ContextDefinitionInterface $requirement, ContextDefinitionInterface $context_definition);
+
+}
diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php b/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php
index 2a13d364d7..01dfef203e 100644
--- a/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php
+++ b/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php
@@ -11,6 +11,23 @@
  */
 class ContextHandler implements ContextHandlerInterface {
 
+  /**
+   * The context constraint handler.
+   *
+   * @var \Drupal\Core\Plugin\Context\ContextConstraintHandlerInterface
+   */
+  protected $contextConstraintHandler;
+
+  /**
+   * ContextHandler constructor.
+   *
+   * @param \Drupal\Core\Plugin\Context\ContextConstraintHandlerInterface $context_constraint_handler
+   *   The context constraint handler.
+   */
+  public function __construct(ContextConstraintHandlerInterface $context_constraint_handler) {
+    $this->contextConstraintHandler = $context_constraint_handler;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -51,11 +68,19 @@ public function getMatchingContexts(array $contexts, ContextDefinitionInterface
         return FALSE;
       }
 
-      // If any constraint does not match, this context is invalid.
-      foreach ($definition->getConstraints() as $constraint_name => $constraint) {
-        if ($context_definition->getConstraint($constraint_name) != $constraint) {
-          return FALSE;
+      // If the definition has constraints, validate the contexts against them.
+      if ($definition->getConstraints()) {
+        if ($context->hasContextValue()) {
+          $context_definition = new ContextDefinition(
+            $context_definition->getDataType(),
+            $context_definition->getLabel(),
+            $context_definition->isRequired(),
+            $context_definition->isMultiple(),
+            $context_definition->getDescription(),
+            $context->getContextData()
+          );
         }
+        return $this->contextConstraintHandler->validateDefinitionConstraints($definition, $context_definition);
       }
 
       // All contexts with matching data type and contexts are valid.
diff --git a/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php b/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php
index 4ed5e6eb60..36bcd996ae 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php
@@ -9,12 +9,15 @@
 
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Component\Plugin\Exception\ContextException;
+use Drupal\Core\Plugin\Context\ContextConstraintHandlerInterface;
 use Drupal\Core\Plugin\Context\ContextDefinition;
 use Drupal\Core\Plugin\Context\ContextHandler;
+use Drupal\Core\Plugin\Context\ContextInterface;
 use Drupal\Core\Plugin\ContextAwarePluginInterface;
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\Core\TypedData\Plugin\DataType\StringData;
 use Drupal\Tests\UnitTestCase;
+use Prophecy\Argument;
 
 /**
  * @coversDefaultClass \Drupal\Core\Plugin\Context\ContextHandler
@@ -35,7 +38,8 @@ class ContextHandlerTest extends UnitTestCase {
   protected function setUp() {
     parent::setUp();
 
-    $this->contextHandler = new ContextHandler();
+    $constraintHandler = $this->prophesize(ContextConstraintHandlerInterface::class);
+    $this->contextHandler = new ContextHandler($constraintHandler->reveal());
   }
 
   /**
@@ -63,19 +67,13 @@ public function providerTestCheckRequirements() {
       ->will($this->returnValue(new ContextDefinition('empty')));
 
     $requirement_specific = new ContextDefinition('specific');
-    $requirement_specific->setConstraints(['bar' => 'baz']);
 
-    $context_constraint_mismatch = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
-    $context_constraint_mismatch->expects($this->atLeastOnce())
-      ->method('getContextDefinition')
-      ->will($this->returnValue(new ContextDefinition('foo')));
     $context_datatype_mismatch = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context_datatype_mismatch->expects($this->atLeastOnce())
       ->method('getContextDefinition')
       ->will($this->returnValue(new ContextDefinition('fuzzy')));
 
     $context_definition_specific = new ContextDefinition('specific');
-    $context_definition_specific->setConstraints(['bar' => 'baz']);
     $context_specific = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context_specific->expects($this->atLeastOnce())
       ->method('getContextDefinition')
@@ -87,7 +85,6 @@ public function providerTestCheckRequirements() {
     $data[] = [[], [$requirement_optional], TRUE];
     $data[] = [[], [$requirement_any, $requirement_optional], FALSE];
     $data[] = [[$context_any], [$requirement_any], TRUE];
-    $data[] = [[$context_constraint_mismatch], [$requirement_specific], FALSE];
     $data[] = [[$context_datatype_mismatch], [$requirement_specific], FALSE];
     $data[] = [[$context_specific], [$requirement_specific], TRUE];
 
@@ -113,22 +110,16 @@ public function providerTestGetMatchingContexts() {
     $requirement_any = new ContextDefinition();
 
     $requirement_specific = new ContextDefinition('specific');
-    $requirement_specific->setConstraints(['bar' => 'baz']);
 
     $context_any = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context_any->expects($this->atLeastOnce())
       ->method('getContextDefinition')
       ->will($this->returnValue(new ContextDefinition('empty')));
-    $context_constraint_mismatch = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
-    $context_constraint_mismatch->expects($this->atLeastOnce())
-      ->method('getContextDefinition')
-      ->will($this->returnValue(new ContextDefinition('foo')));
     $context_datatype_mismatch = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context_datatype_mismatch->expects($this->atLeastOnce())
       ->method('getContextDefinition')
       ->will($this->returnValue(new ContextDefinition('fuzzy')));
     $context_definition_specific = new ContextDefinition('specific');
-    $context_definition_specific->setConstraints(['bar' => 'baz']);
     $context_specific = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context_specific->expects($this->atLeastOnce())
       ->method('getContextDefinition')
@@ -141,9 +132,6 @@ public function providerTestGetMatchingContexts() {
     $data[] = [[$context_any], $requirement_any];
     // A context with a specific matching requirement is valid.
     $data[] = [[$context_specific], $requirement_specific];
-
-    // A context with a mismatched constraint is invalid.
-    $data[] = [[$context_constraint_mismatch], $requirement_specific, []];
     // A context with a mismatched datatype is invalid.
     $data[] = [[$context_datatype_mismatch], $requirement_specific, []];
 
@@ -195,29 +183,13 @@ public function providerTestFilterPluginDefinitionsByContexts() {
     // Satisfied context, all plugins available.
     $data[] = [TRUE, $plugins, $plugins];
 
-    $mismatched_context_definition = (new ContextDefinition('expected_data_type'))->setConstraints(['mismatched_constraint_name' => 'mismatched_constraint_value']);
-    $plugins = ['expected_plugin' => ['context' => ['context1' => $mismatched_context_definition]]];
-    // Mismatched constraints, no plugins available.
-    $data[] = [TRUE, $plugins, []];
-
-    $optional_mismatched_context_definition = clone $mismatched_context_definition;
-    $optional_mismatched_context_definition->setRequired(FALSE);
-    $plugins = ['expected_plugin' => ['context' => ['context1' => $optional_mismatched_context_definition]]];
-    // Optional mismatched constraint, all plugins available.
-    $data[] = [FALSE, $plugins, $plugins];
-
-    $expected_context_definition = (new ContextDefinition('expected_data_type'))->setConstraints(['expected_constraint_name' => 'expected_constraint_value']);
-    $plugins = ['expected_plugin' => ['context' => ['context1' => $expected_context_definition]]];
-    // Satisfied context with constraint, all plugins available.
-    $data[] = [TRUE, $plugins, $plugins];
-
-    $optional_expected_context_definition = clone $expected_context_definition;
+    $optional_expected_context_definition = new ContextDefinition('expected_data_type');
     $optional_expected_context_definition->setRequired(FALSE);
     $plugins = ['expected_plugin' => ['context' => ['context1' => $optional_expected_context_definition]]];
     // Optional unsatisfied context, all plugins available.
     $data[] = [FALSE, $plugins, $plugins];
 
-    $unexpected_context_definition = (new ContextDefinition('unexpected_data_type'))->setConstraints(['mismatched_constraint_name' => 'mismatched_constraint_value']);
+    $unexpected_context_definition = new ContextDefinition('unexpected_data_type');
     $plugins = [
       'unexpected_plugin' => ['context' => ['context1' => $unexpected_context_definition]],
       'expected_plugin' => ['context' => ['context2' => new ContextDefinition('expected_data_type')]],
