diff --git a/core/lib/Drupal/Component/Plugin/Context/Context.php b/core/lib/Drupal/Component/Plugin/Context/Context.php
new file mode 100644
index 0000000..ce8ccf4
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Context/Context.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Component\Plugin\Context\Context.
+ */
+
+namespace Drupal\Component\Plugin\Context;
+
+use Drupal\Component\Plugin\Exception\ContextException;
+
+/**
+ * A generic context wrapper class.
+ */
+class Context {
+
+  /**
+   * The context.
+   *
+   * @var mixed
+   */
+  protected $context;
+
+  /**
+   * The class name or an array definition to which a context must conform.
+   *
+   * @var mixed
+   *  A string or array.
+   */
+  protected $contextDefinition;
+
+  public function __construct($contextDefinition) {
+    $this->contextDefinition = $contextDefinition;
+  }
+
+  public function setContext($context) {
+    $context = $this->validate($context);
+    $this->context = $context;
+  }
+
+  public function getContext() {
+    return $this->context;
+  }
+
+  public function validate($context) {
+    if (is_string($this->contextDefinition)) {
+      if ($context instanceof $this->contextDefinition) {
+        return $context;
+      }
+      throw new ContextException("The context passed was not an instance of $this->contextDefinition.");
+    }
+    throw new ContextException("An error was encountered while trying to validate the context.");
+  }
+
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Component/Plugin/ContextualPluginBase.php b/core/lib/Drupal/Component/Plugin/ContextualPluginBase.php
new file mode 100644
index 0000000..da3216a
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/ContextualPluginBase.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\Component\Plugin\ContextualPluginBase
+ */
+
+namespace Drupal\Component\Plugin;
+
+use Drupal\Component\Plugin\Exception\PluginException;
+use Drupal\Component\Plugin\Context\Context;
+
+/**
+ * Base class for plugins that use context.
+ */
+abstract class ContextualPluginBase extends PluginBase {
+
+  /**
+   * Returns the context definitions of the plugin.
+   *
+   * @return mixed
+   *   The context definitions if set, otherwise NULL.
+   */
+  public function getContextDefinitions() {
+    $definition = $this->getDefinition();
+    return !empty($definition['context']) ? $definition['context'] : NULL;
+  }
+
+  /**
+   * Returns the a specific context class definition of the plugin.
+   *
+   * @return string
+   *   The name of a class to which the set context must conform.
+   */
+  public function getContextDefinition($key) {
+    $definition = $this->getDefinition();
+    if (empty($definition['context'][$key])) {
+      throw new PluginException("The $key context is not a valid context.");
+    }
+    return $definition['context'][$key];
+  }
+
+  /**
+   * Returns the wrappers for set values for all defined contexts.
+   *
+   * @return array
+   *   Returns the array of all set context wrappers.
+   */
+  public function getContextsWrappers() {
+    $definition = $this->getDefinition();
+    // If there are no contexts defined by the plugin, return an empty array.
+    if (empty($definition['context'])) {
+      return array();
+    }
+    if (empty($this->configuration['context'])) {
+      throw new PluginException("There are no set contexts.");
+    }
+    $contexts = array();
+    foreach (array_keys($definition['context']) as $key) {
+      if (empty($this->configuration['context'][$key])) {
+        throw new PluginException("The $key context is not yet set.");
+      }
+      $contexts[$key] = $this->configuration['context'][$key];
+    }
+    return $contexts;
+  }
+
+  /**
+   * Returns the set context wrapper for a defined context.
+   *
+   * @return object
+   *   Returns a context wrapper object.
+   */
+  public function getContextWrapper($key) {
+    $definition = $this->getDefinition();
+    if (empty($definition['context'][$key])) {
+      throw new PluginException("The $key context is not a valid context.");
+    }
+    if (empty($this->configuration['context'][$key])) {
+      throw new PluginException("The $key context is not yet set.");
+    }
+
+    return $this->configuration['context'][$key];
+  }
+
+  /**
+   * Returns the set values for all defined contexts.
+   *
+   * @return array
+   *   Returns the array of all set contexts.
+   */
+  public function getContexts() {
+    $contexts = array();
+    foreach ($this->getContextsWrappers() as $key => $context) {
+      $contexts[$key] = $context->getContext();
+    }
+    return $contexts;
+  }
+
+  /**
+   * Returns the set value for a defined context.
+   *
+   * @return object
+   *   Returns instantiated object of a context.
+   */
+  public function getContext($key) {
+    return $this->getContextWrapper($key)->getContext();
+  }
+
+  /**
+   * Sets a defined context to the passed value.
+   *
+   * @return $this
+   *   Returns the plugin instance.
+   */
+  public function setContext($key, $value) {
+    $class = $this->getContextDefinition($key);
+    $this->configuration['context'][$key] = new Context($class);
+    $this->configuration['context'][$key]->setContext($value);
+
+    return $this;
+  }
+
+}
diff --git a/core/lib/Drupal/Component/Plugin/Exception/ContextException.php b/core/lib/Drupal/Component/Plugin/Exception/ContextException.php
new file mode 100644
index 0000000..fbb1c2d
--- /dev/null
+++ b/core/lib/Drupal/Component/Plugin/Exception/ContextException.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\Component\Plugin\Exception\ContextException.
+ */
+
+namespace Drupal\Component\Plugin\Exception;
+
+use Exception;
+
+/**
+ * Generic Plugin exception class to be thrown when no more specific class
+ * is applicable.
+ */
+class ContextException extends Exception implements ExceptionInterface { }
diff --git a/core/lib/Drupal/Core/Plugin/Context/Context.php b/core/lib/Drupal/Core/Plugin/Context/Context.php
new file mode 100644
index 0000000..cf919d5
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/Context/Context.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Plugin\Context\Context.
+ */
+
+namespace Drupal\Core\Plugin\Context;
+
+use Drupal\Component\Plugin\Context\Context as ComponentContext;
+use Drupal\Component\Plugin\Exception\ContextException;
+use Drupal\Core\TypedData\TypedDataManager;
+
+/**
+ * A Drupal specific context wrapper class.
+ *
+ * The validate method is specifically overridden in order to support typed
+ * data definitions instead of just class names in the contextual definitions
+ * of plugins that extend ContextualPluginBase.
+ */
+class Context extends ComponentContext {
+
+  /**
+   * Override for Drupal\Component\Plugin\Context\Context::validate().
+   */
+  public function validate($context) {
+    // Check to make sure we have a class name, and that the passed context is
+    // an instance of that class name.
+    if (is_string($this->contextDefinition)) {
+      if ($context instanceof $this->contextDefinition) {
+        return $context;
+      }
+      throw new ContextException("The context passed was not an instance of $this->contextDefinition.");
+    }
+    // Check to see if we have a typed data definition instead of a class name.
+    if (is_array($this->contextDefinition)) {
+      $typed_data_manager = new TypedDataManager();
+      $typed_data = $typed_data_manager->create($this->contextDefinition, $context);
+      // If we do have a typed data definition, validate it and return the
+      // typed data instance instead.
+      if ($typed_data->validate()) {
+        return $typed_data;
+      }
+      throw new ContextException("The context passed could not be validated through typed data.");
+    }
+    throw new ContextException("An error was encountered while trying to validate the context.");
+  }
+
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Plugin/ContextualPluginBase.php b/core/lib/Drupal/Core/Plugin/ContextualPluginBase.php
new file mode 100644
index 0000000..ea47c33
--- /dev/null
+++ b/core/lib/Drupal/Core/Plugin/ContextualPluginBase.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\Core\Plugin\ContextualPluginBase
+ */
+
+namespace Drupal\Core\Plugin;
+
+use Drupal\Component\Plugin\ContextualPluginBase as PluginBase;
+use Drupal\Core\Plugin\Context\Context;
+
+/**
+ * Drupal specific class for plugins that use context.
+ *
+ * This class specifically overrides setContext to use the core version of
+ * the Context wrapper class. This code is exactly the same as what is in
+ * Component ContextualPluginBase but it is using a different Context class.
+ */
+abstract class ContextualPluginBase extends PluginBase {
+
+  /**
+   * Override of Drupal\Component\Plugin\ContextualPluginBase::setContext().
+   */
+  public function setContext($key, $value) {
+    $class = $this->getContextDefinition($key);
+    $this->configuration['context'][$key] = new Context($class);
+    $this->configuration['context'][$key]->setContext($value);
+
+    return $this;
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
new file mode 100644
index 0000000..fe70c8b
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
@@ -0,0 +1,190 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\Plugin\ContextPluginTest.
+ */
+
+namespace Drupal\system\Tests\Plugin;
+
+use Drupal\simpletest\DrupalUnitTestBase;
+use Drupal\plugin_test\Plugin\MockBlockManager;
+use Drupal\Component\Plugin\Exception\PluginException;
+use Drupal\Component\Plugin\Exception\ContextException;
+
+/**
+ * Tests that derivative plugins are correctly discovered.
+ */
+class ContextPluginTest extends DrupalUnitTestBase {
+
+  public static $modules = array('system', 'user', 'node');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Contextual Plugins',
+      'description' => 'Tests that contexts are properly set and working within plugins.',
+      'group' => 'Plugin API',
+    );
+  }
+
+  protected function setUp() {
+    parent::setUp();
+    $this->installSchema('node', 'node_type');
+  }
+
+  /**
+   * Tests getDefinitions() and getDefinition() with a derivativeDecorator.
+   */
+  function testContext() {
+    $name = $this->randomName();
+    $manager = new MockBlockManager();
+    $plugin = $manager->createInstance('user_name');
+    // Create a node, add it as context, catch the exception.
+    $node = entity_create('node', array('title' => $name));
+
+    // Try to get a valid context wrapper that has not been set.
+    try {
+      $plugin->getContextWrapper('user');
+    }
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'The user context is not yet set.');
+    }
+
+    // Try to get an invalid context wrapper.
+    try {
+      $plugin->getContextWrapper('node');
+    }
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'The node context is not a valid context.');
+    }
+
+    // Try to get a valid context that has not been set.
+    try {
+      $plugin->getContext('user');
+    }
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'The user context is not yet set.');
+    }
+
+    // Try to call a method of the plugin that requires context before it has
+    // been set.
+    try {
+      $plugin->getTitle();
+    }
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'The user context is not yet set.');
+    }
+
+    // Try to get a context that is not valid.
+    try {
+      $plugin->getContext('node');
+    }
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'The node context is not a valid context.');
+    }
+
+    // Try to pass the wrong class type as a context.
+    try {
+      $plugin->setContext('user', $node);
+    }
+    catch (ContextException $e) {
+      $this->assertEqual($e->getMessage(), 'The context passed was not an instance of Drupal\user\Plugin\Core\Entity\User.');
+    }
+
+    // Set an appropriate context appropriately and check to make sure its
+    // methods work as expected.
+    $user = entity_create('user', array('name' => $name));
+    $plugin->setContext('user', $user);
+    $this->assertEqual($user->label(), $plugin->getTitle());
+
+    // Test the getContextDefinitions() method.
+    $this->assertIdentical($plugin->getContextDefinitions(), array('user' => 'Drupal\user\Plugin\Core\Entity\User'));
+
+    // Test the getContextDefinition() method for a valid context.
+    $this->assertEqual($plugin->getContextDefinition('user'), 'Drupal\user\Plugin\Core\Entity\User');
+
+    // Test the getContextDefinition() method for an invalid context.
+    try {
+      $plugin->getContextDefinition('node');
+    }
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'The node context is not a valid context.');
+    }
+
+    // Test TypedData Context Plugins
+    $typed_data_plugin = $manager->createInstance('string_context');
+
+    // Try to get a valid context that has not been set.
+    try {
+      $typed_data_plugin->getContext('string');
+    }
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'The string context is not yet set.');
+    }
+
+    // Try to call a method of the plugin that requires context before it has
+    // been set.
+    try {
+      $typed_data_plugin->getTitle();
+    }
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'The string context is not yet set.');
+    }
+
+    // Set the context appropriately and check the title.
+    $typed_data_plugin->setContext('string', $name);
+    $this->assertEqual($name, $typed_data_plugin->getTitle());
+
+    // Test Complex compound contexts.
+    $complex_plugin = $manager->createInstance('complex_context');
+
+    // With no contexts set, get the context wrappers.
+    try {
+      $complex_plugin->getContextsWrappers();
+    }
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'There are no set contexts.');
+    }
+
+    // With no contexts set, get the contexts.
+    try {
+      $complex_plugin->getContexts();
+    }
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'There are no set contexts.');
+    }
+
+    // Set the user context.
+    $complex_plugin->setContext('user', $user);
+
+    // With only the user context set, get the context wrappers.
+    try {
+      $complex_plugin->getContextsWrappers();
+    }
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'The node context is not yet set.');
+    }
+
+    // With only the user context set, get the contexts.
+    try {
+      $complex_plugin->getContexts();
+    }
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'The node context is not yet set.');
+    }
+
+    $complex_plugin->setContext('node', $node);
+    $context_wrappers = $complex_plugin->getContextsWrappers();
+    // Make sure what came out of the wrappers is good.
+    $this->assertEqual($context_wrappers['user']->getContext()->label(), $user->label());
+    $this->assertEqual($context_wrappers['node']->getContext()->label(), $node->label());
+
+    // Make sure what comes out of Contexts is good.
+    $contexts = $complex_plugin->getContexts();
+    $this->assertEqual($contexts['user']->label(), $user->label());
+    $this->assertEqual($contexts['node']->label(), $node->label());
+
+    // Test the title method for the complex context plugin.
+    $this->assertEqual($user->label() . ' -- ' . $node->label(), $complex_plugin->getTitle());
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php
index 5db9322..32553d5 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php
@@ -70,6 +70,28 @@ public function setUp() {
         'label' => 'Layout Foo',
         'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlock',
       ),
+      'user_name' => array(
+        'label' => 'User Name',
+        'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserNameBlock',
+        'context' => array(
+          'user' => 'Drupal\user\Plugin\Core\Entity\User'
+        ),
+      ),
+      'string_context' => array(
+        'label' => 'String Typed Data',
+        'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\TypedDataStringBlock',
+        'context' => array(
+          'string' => array('type' => 'string'),
+        ),
+      ),
+      'complex_context' => array(
+        'label' => 'Complex Context',
+        'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockComplexContextBlock',
+        'context' => array(
+          'user' => 'Drupal\user\Plugin\Core\Entity\User',
+          'node' => 'Drupal\node\Plugin\Core\Entity\Node',
+        ),
+      ),
     );
     $this->defaultsTestPluginExpectedDefinitions = array(
       'test_block1' => array(
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
index fcf1824..042bd22 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
@@ -66,6 +66,35 @@ public function __construct() {
       'derivative' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockLayoutBlockDeriver',
     ));
 
+    // A block plugin that requires context to function. This block requires a
+    // user object in order to return the user name from the getTitle() method.
+    $this->discovery->setDefinition('user_name', array(
+      'label' => t('User Name'),
+      'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserNameBlock',
+      'context' => array(
+        'user' => 'Drupal\user\Plugin\Core\Entity\User'
+      ),
+    ));
+
+    // A block plugin that requires a typed data string context to function.
+    $this->discovery->setDefinition('string_context', array(
+      'label' => t('String Typed Data'),
+      'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\TypedDataStringBlock',
+      'context' => array(
+        'string' => array('type' => 'string'),
+      ),
+    ));
+
+    // A complex context plugin that requires both a user and node for context.
+    $this->discovery->setDefinition('complex_context', array(
+      'label' => t('Complex Context'),
+      'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockComplexContextBlock',
+      'context' => array(
+        'user' => 'Drupal\user\Plugin\Core\Entity\User',
+        'node' => 'Drupal\node\Plugin\Core\Entity\Node',
+      ),
+    ));
+
     // In addition to finding all of the plugins available for a type, a plugin
     // type must also be able to create instances of that plugin. For example, a
     // specific instance of a "Main menu" menu block, configured to show just
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockComplexContextBlock.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockComplexContextBlock.php
new file mode 100644
index 0000000..fe25bc2
--- /dev/null
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockComplexContextBlock.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\plugin_test\Plugin\plugin_test\mock_block\MockComplexContextBlock.
+ */
+
+namespace Drupal\plugin_test\Plugin\plugin_test\mock_block;
+
+use Drupal\Core\Plugin\ContextualPluginBase;
+
+/**
+ * Implementation of a complex context plugin used by Plugin API context tests.
+ *
+ * @see Drupal\plugin_test\Plugin\MockBlockManager
+ */
+class MockComplexContextBlock extends ContextualPluginBase {
+
+  public function getTitle() {
+    $user = $this->getContext('user');
+    $node = $this->getContext('node');
+    return $user->label() . ' -- ' . $node->label();
+  }
+}
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockUserNameBlock.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockUserNameBlock.php
new file mode 100644
index 0000000..86b4365
--- /dev/null
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/MockUserNameBlock.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserNameBlock.
+ */
+
+namespace Drupal\plugin_test\Plugin\plugin_test\mock_block;
+
+use Drupal\Core\Plugin\ContextualPluginBase;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+
+/**
+ * Implementation of a user name block plugin used by Plugin API context test.
+ *
+ * @see Drupal\plugin_test\Plugin\MockBlockManager
+ */
+class MockUserNameBlock extends ContextualPluginBase {
+
+  public function getTitle() {
+    $user = $this->getContext('user');
+    return $user->label();
+  }
+}
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/TypedDataStringBlock.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/TypedDataStringBlock.php
new file mode 100644
index 0000000..2c62f49
--- /dev/null
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/plugin_test/mock_block/TypedDataStringBlock.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\plugin_test\Plugin\plugin_test\mock_block\TypedDataStringBlock.
+ */
+
+namespace Drupal\plugin_test\Plugin\plugin_test\mock_block;
+
+use Drupal\Core\Plugin\ContextualPluginBase;
+
+/**
+ * Implementation of a String TypedData contextual block plugin used by Plugin
+ * API context test.
+ *
+ * @see Drupal\plugin_test\Plugin\MockBlockManager
+ */
+class TypedDataStringBlock extends ContextualPluginBase {
+
+  public function getTitle() {
+    $context = $this->getContext('string');
+    return $context->getValue();
+  }
+}
