diff --git a/core/lib/Drupal/Component/Plugin/Context/ContextInterface.php b/core/lib/Drupal/Component/Plugin/Context/ContextInterface.php
index f22202b..ab092ed 100644
--- a/core/lib/Drupal/Component/Plugin/Context/ContextInterface.php
+++ b/core/lib/Drupal/Component/Plugin/Context/ContextInterface.php
@@ -42,7 +42,7 @@ public function setContextDefinition(ContextDefinitionInterface $context_definit
   /**
    * Gets the provided definition that the context must conform to.
    *
-   * @return array
+   * @return \Drupal\Component\Plugin\Context\ContextDefinitionInterface
    *   The defining characteristic representation of the context.
    */
   public function getContextDefinition();
diff --git a/core/lib/Drupal/Core/Annotation/ContextDefinition.php b/core/lib/Drupal/Core/Annotation/ContextDefinition.php
index 25bc272..98e3406 100644
--- a/core/lib/Drupal/Core/Annotation/ContextDefinition.php
+++ b/core/lib/Drupal/Core/Annotation/ContextDefinition.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Contains \Drupal\Core\Annotation\ContextDefinition.
@@ -6,6 +7,8 @@
 
 namespace Drupal\Core\Annotation;
 
+use Drupal\Component\Annotation\Plugin;
+
 /**
  * @defgroup plugin_context context definition plugin metadata
  *
@@ -46,7 +49,6 @@
  * @endcode
  * @}
  */
-use Drupal\Component\Annotation\Plugin;
 
 /**
  * Defines a context definition annotation object.
diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php
index 93a639f..6f61026 100644
--- a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php
+++ b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Plugin\Context;
 
+use Drupal\Component\Utility\String;
 use Drupal\Core\TypedData\TypedDataTrait;
 
 /**
@@ -217,6 +218,10 @@ public function getDataDefinition() {
     else {
       $definition = $this->getTypedDataManager()->createDataDefinition($this->getDataType());
     }
+
+    if (!$definition) {
+      throw new \Exception(String::format('The data type "@type" is invalid', array('@type' => $this->getDataType())));
+    }
     $definition->setLabel($this->getLabel())
       ->setDescription($this->getDescription())
       ->setRequired($this->isRequired())
diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php b/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php
index 100bf29..3638f9c 100644
--- a/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php
+++ b/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php
@@ -8,7 +8,6 @@
 namespace Drupal\Core\Plugin\Context;
 
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
-use Drupal\Component\Plugin\Context\ContextInterface as ComponentContextInterface;
 use Drupal\Component\Plugin\ContextAwarePluginInterface;
 use Drupal\Component\Plugin\Exception\ContextException;
 use Drupal\Component\Utility\String;
@@ -51,19 +50,20 @@ public function filterPluginDefinitionsByContexts(array $contexts, array $defini
       // Build an array of requirements out of the contexts specified by the
       // plugin definition.
       $requirements = array();
+      /** @var $plugin_context \Drupal\Core\Plugin\Context\ContextDefinitionInterface */
       foreach ($plugin_definition['context'] as $context_id => $plugin_context) {
-        $definition = $this->typedDataManager->getDefinition($plugin_context['type']);
-        $definition['type'] = $plugin_context['type'];
+        $definition = $this->typedDataManager->getDefinition($plugin_context->getDataType());
+        $definition['type'] = $plugin_context->getDataType();
 
         // If the plugin specifies additional constraints, add them to the
         // constraints defined by the plugin type.
-        if (isset($plugin_context['constraints'])) {
+        if ($plugin_constraints = $plugin_context->getConstraints()) {
           // Ensure the array exists before adding in constraints.
           if (!isset($definition['constraints'])) {
             $definition['constraints'] = array();
           }
 
-          $definition['constraints'] += $plugin_context['constraints'];
+          $definition['constraints'] += $plugin_constraints;
         }
 
         // Assume the requirement is required if unspecified.
@@ -97,9 +97,8 @@ public function checkRequirements(array $contexts, array $requirements) {
    * {@inheritdoc}
    */
   public function getMatchingContexts(array $contexts, DataDefinitionInterface $definition) {
-    return array_filter($contexts, function (ComponentContextInterface $context) use ($definition) {
-      // @todo getContextDefinition() should return a DataDefinitionInterface.
-      $context_definition = new DataDefinition($context->getContextDefinition());
+    return array_filter($contexts, function (ContextInterface $context) use ($definition) {
+      $context_definition = $context->getContextDefinition()->getDataDefinition();
 
       // If the data types do not match, this context is invalid.
       if ($definition->getDataType() != $context_definition->getDataType()) {
diff --git a/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestContextAwareBlock.php b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestContextAwareBlock.php
index ae2550b..0b94414 100644
--- a/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestContextAwareBlock.php
+++ b/core/modules/block/tests/modules/block_test/src/Plugin/Block/TestContextAwareBlock.php
@@ -16,9 +16,7 @@
  *   id = "test_context_aware",
  *   admin_label = @Translation("Test context-aware block"),
  *   context = {
- *     "user" = {
- *       "type" = "entity:user"
- *     }
+ *     "user" = @ContextDefinition("entity:user")
  *   }
  * )
  */
diff --git a/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php b/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php
index fa7c80c..1569ef7 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php
@@ -9,8 +9,10 @@
 
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Component\Plugin\ContextAwarePluginInterface;
+use Drupal\Core\Plugin\Context\ContextDefinition;
 use Drupal\Core\Plugin\Context\ContextHandler;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\TypedData\DataDefinition;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -63,6 +65,17 @@ protected function setUp() {
     $this->typedDataManager->expects($this->any())
       ->method('getDefaultConstraints')
       ->will($this->returnValue(array()));
+    $this->typedDataManager->expects($this->any())
+      ->method('createDataDefinition')
+      ->will($this->returnValueMap(array(
+        array('expected_data_type', new DataDefinition(array('type' => 'expected_data_type'))),
+        array('mismatched_data_type', new DataDefinition(array('type' => 'mismatched_data_type'))),
+        array('unexpected_data_type', new DataDefinition(array('type' => 'unexpected_data_type'))),
+        array('empty', new DataDefinition(array())),
+        array('foo', new DataDefinition(array('type' => 'foo'))),
+        array('fuzzy', new DataDefinition(array('type' => 'fuzzy'))),
+        array('specific', new DataDefinition(array('type' => 'foo'))),
+      )));
     $this->contextHandler = new ContextHandler($this->typedDataManager);
 
     $container = new ContainerBuilder();
@@ -99,10 +112,10 @@ public function providerTestCheckRequirements() {
       ->method('getConstraints')
       ->will($this->returnValue(array()));
 
-    $context_any = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+    $context_any = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context_any->expects($this->atLeastOnce())
       ->method('getContextDefinition')
-      ->will($this->returnValue(array()));
+      ->will($this->returnValue(new ContextDefinition('empty')));
 
     $requirement_specific = $this->getMock('Drupal\Core\TypedData\DataDefinitionInterface');
     $requirement_specific->expects($this->atLeastOnce())
@@ -115,19 +128,21 @@ public function providerTestCheckRequirements() {
       ->method('getConstraints')
       ->will($this->returnValue(array('bar' => 'baz')));
 
-    $context_constraint_mismatch = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+    $context_constraint_mismatch = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context_constraint_mismatch->expects($this->atLeastOnce())
       ->method('getContextDefinition')
-      ->will($this->returnValue(array('type' => 'foo')));
-    $context_datatype_mismatch = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+      ->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(array('type' => 'fuzzy')));
+      ->will($this->returnValue(new ContextDefinition('fuzzy')));
 
-    $context_specific = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+    $context_definition_specific = new ContextDefinition('specific');
+    $context_definition_specific->setConstraints(array('bar' => 'baz'));
+    $context_specific = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context_specific->expects($this->atLeastOnce())
       ->method('getContextDefinition')
-      ->will($this->returnValue(array('type' => 'foo', 'constraints' => array('bar' => 'baz'))));
+      ->will($this->returnValue($context_definition_specific));
 
     $data = array();
     $data[] = array(array(), array(), TRUE);
@@ -179,22 +194,24 @@ public function providerTestGetMatchingContexts() {
       ->method('getConstraints')
       ->will($this->returnValue(array('bar' => 'baz')));
 
-    $context_any = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+    $context_any = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context_any->expects($this->atLeastOnce())
       ->method('getContextDefinition')
-      ->will($this->returnValue(array()));
-    $context_constraint_mismatch = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+      ->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(array('type' => 'foo')));
-    $context_datatype_mismatch = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+      ->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(array('type' => 'fuzzy')));
-    $context_specific = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+      ->will($this->returnValue(new ContextDefinition('fuzzy')));
+    $context_definition_specific = new ContextDefinition('specific');
+    $context_definition_specific->setConstraints(array('bar' => 'baz'));
+    $context_specific = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context_specific->expects($this->atLeastOnce())
       ->method('getContextDefinition')
-      ->will($this->returnValue(array('type' => 'foo', 'constraints' => array('bar' => 'baz'))));
+      ->will($this->returnValue($context_definition_specific));
 
     $data = array();
     // No context will return no valid contexts.
@@ -217,7 +234,19 @@ public function providerTestGetMatchingContexts() {
    *
    * @dataProvider providerTestFilterPluginDefinitionsByContexts
    */
-  public function testFilterPluginDefinitionsByContexts($contexts, $definitions, $expected, $typed_data_definition = NULL) {
+  public function testFilterPluginDefinitionsByContexts($has_context, $definitions, $expected, $typed_data_definition = NULL) {
+    if ($has_context) {
+      $context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
+      $expected_context_definition = (new ContextDefinition('expected_data_type'))->setConstraints(array('expected_constraint_name' => 'expected_constraint_value'));
+      $context->expects($this->atLeastOnce())
+        ->method('getContextDefinition')
+        ->will($this->returnValue($expected_context_definition));
+      $contexts = array($context);
+    }
+    else {
+      $contexts = array();
+    }
+
     if ($typed_data_definition) {
       $this->typedDataManager->expects($this->atLeastOnce())
         ->method('getDefinition')
@@ -231,69 +260,67 @@ public function testFilterPluginDefinitionsByContexts($contexts, $definitions, $
    * Provides data for testFilterPluginDefinitionsByContexts().
    */
   public function providerTestFilterPluginDefinitionsByContexts() {
-    $context = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
-    $context->expects($this->atLeastOnce())
-      ->method('getContextDefinition')
-      ->will($this->returnValue(array('type' => 'expected_data_type', 'constraints' => array('expected_constraint_name' => 'expected_constraint_value'))));
-
     $data = array();
 
     $plugins = array();
     // No context and no plugins, no plugins available.
-    $data[] = array(array(), $plugins, array());
+    $data[] = array(FALSE, $plugins, array());
 
     $plugins = array('expected_plugin' => array());
     // No context, all plugins available.
-    $data[] = array(array(), $plugins, $plugins);
+    $data[] = array(FALSE, $plugins, $plugins);
 
     $plugins = array('expected_plugin' => array('context' => array()));
     // No context, all plugins available.
-    $data[] = array(array(), $plugins, $plugins);
+    $data[] = array(FALSE, $plugins, $plugins);
 
-    $plugins = array('expected_plugin' => array('context' => array('context1' => array('type' => 'expected_data_type'))));
+    $plugins = array('expected_plugin' => array('context' => array('context1' => new ContextDefinition('expected_data_type'))));
     // Missing context, no plugins available.
     $data[] = array(array(), $plugins, array());
     // Satisfied context, all plugins available.
-    $data[] = array(array($context), $plugins, $plugins);
+    $data[] = array(TRUE, $plugins, $plugins);
 
-    $plugins = array('expected_plugin' => array('context' => array('context1' => array('type' => 'expected_data_type', 'constraints' => array('mismatched_constraint_name' => 'mismatched_constraint_value')))));
+    $mismatched_context_definition = (new ContextDefinition('expected_data_type'))->setConstraints(array('mismatched_constraint_name' => 'mismatched_constraint_value'));
+    $plugins = array('expected_plugin' => array('context' => array('context1' => $mismatched_context_definition)));
     // Mismatched constraints, no plugins available.
-    $data[] = array(array($context), $plugins, array());
+    $data[] = array(TRUE, $plugins, array());
 
-    $plugins = array('expected_plugin' => array('context' => array('context1' => array('type' => 'expected_data_type', 'constraints' => array('expected_constraint_name' => 'expected_constraint_value')))));
+    $expected_context_definition = (new ContextDefinition('expected_data_type'))->setConstraints(array('expected_constraint_name' => 'expected_constraint_value'));
+    $plugins = array('expected_plugin' => array('context' => array('context1' => $expected_context_definition)));
     // Satisfied context with constraint, all plugins available.
-    $data[] = array(array($context), $plugins, $plugins);
+    $data[] = array(TRUE, $plugins, $plugins);
 
     $typed_data = array(array('expected_data_type', TRUE, array('required' => FALSE)));
     // Optional unsatisfied context from TypedData, all plugins available.
-    $data[] = array(array(), $plugins, $plugins, $typed_data);
+    $data[] = array(FALSE, $plugins, $plugins, $typed_data);
 
     $typed_data = array(array('expected_data_type', TRUE, array('required' => TRUE)));
     // Required unsatisfied context from TypedData, no plugins available.
-    $data[] = array(array(), $plugins, array(), $typed_data);
+    $data[] = array(FALSE, $plugins, array(), $typed_data);
 
     $typed_data = array(array('expected_data_type', TRUE, array('constraints' => array('mismatched_constraint_name' => 'mismatched_constraint_value'), 'required' => FALSE)));
     // Optional mismatched constraint from TypedData, all plugins available.
-    $data[] = array(array(), $plugins, $plugins, $typed_data);
+    $data[] = array(FALSE, $plugins, $plugins, $typed_data);
 
     $typed_data = array(array('expected_data_type', TRUE, array('constraints' => array('mismatched_constraint_name' => 'mismatched_constraint_value'), 'required' => TRUE)));
     // Required mismatched constraint from TypedData, no plugins available.
-    $data[] = array(array(), $plugins, array(), $typed_data);
+    $data[] = array(FALSE, $plugins, array(), $typed_data);
 
     $typed_data = array(array('expected_data_type', TRUE, array('constraints' => array('expected_constraint_name' => 'expected_constraint_value'))));
     // Satisfied constraint from TypedData, all plugins available.
-    $data[] = array(array($context), $plugins, $plugins, $typed_data);
+    $data[] = array(TRUE, $plugins, $plugins, $typed_data);
 
+    $unexpected_context_definition = (new ContextDefinition('unexpected_data_type'))->setConstraints(array('mismatched_constraint_name' => 'mismatched_constraint_value'));
     $plugins = array(
-      'unexpected_plugin' => array('context' => array('context1' => array('type' => 'unexpected_data_type', 'constraints' => array('mismatched_constraint_name' => 'mismatched_constraint_value')))),
-      'expected_plugin' => array('context' => array('context2' => array('type' => 'expected_data_type'))),
+      'unexpected_plugin' => array('context' => array('context1' => $unexpected_context_definition)),
+      'expected_plugin' => array('context' => array('context2' => new ContextDefinition('expected_data_type'))),
     );
     $typed_data = array(
       array('unexpected_data_type', TRUE, array()),
       array('expected_data_type', TRUE, array('constraints' => array('expected_constraint_name' => 'expected_constraint_value'))),
     );
     // Context only satisfies one plugin.
-    $data[] = array(array($context), $plugins, array('expected_plugin' => $plugins['expected_plugin']), $typed_data);
+    $data[] = array(TRUE, $plugins, array('expected_plugin' => $plugins['expected_plugin']), $typed_data);
 
     return $data;
   }
@@ -302,11 +329,11 @@ public function providerTestFilterPluginDefinitionsByContexts() {
    * @covers ::applyContextMapping
    */
   public function testApplyContextMapping() {
-    $context_hit = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+    $context_hit = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context_hit->expects($this->atLeastOnce())
       ->method('getContextValue')
       ->will($this->returnValue(array('foo')));
-    $context_miss = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+    $context_miss = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context_miss->expects($this->never())
       ->method('getContextValue');
 
@@ -330,7 +357,7 @@ public function testApplyContextMapping() {
    * @covers ::applyContextMapping
    */
   public function testApplyContextMappingConfigurable() {
-    $context = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+    $context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context->expects($this->never())
       ->method('getContextValue');
 
@@ -352,7 +379,7 @@ public function testApplyContextMappingConfigurable() {
    * @covers ::applyContextMapping
    */
   public function testApplyContextMappingConfigurableAssigned() {
-    $context = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+    $context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context->expects($this->atLeastOnce())
       ->method('getContextValue')
       ->will($this->returnValue(array('foo')));
@@ -379,7 +406,7 @@ public function testApplyContextMappingConfigurableAssigned() {
    * @expectedExceptionMessage Assigned contexts were not satisfied: miss
    */
   public function testApplyContextMappingConfigurableAssignedMiss() {
-    $context = $this->getMock('Drupal\Component\Plugin\Context\ContextInterface');
+    $context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
     $context->expects($this->never())
       ->method('getContextValue');
 
