diff --git a/core/lib/Drupal/Component/Plugin/Context/Context.php b/core/lib/Drupal/Component/Plugin/Context/Context.php
index 9f4396b..b117a72 100644
--- a/core/lib/Drupal/Component/Plugin/Context/Context.php
+++ b/core/lib/Drupal/Component/Plugin/Context/Context.php
@@ -8,6 +8,8 @@
 namespace Drupal\Component\Plugin\Context;
 
 use Drupal\Component\Plugin\Exception\ContextException;
+use Symfony\Component\Validator\Constraints\Type;
+use Symfony\Component\Validator\Validation;
 
 /**
  * A generic context class for wrapping data a plugin needs to operate.
@@ -39,7 +41,6 @@ public function __construct(array $context_definition) {
    * Implements \Drupal\Component\Plugin\Context\ContextInterface::setContextValue().
    */
   public function setContextValue($value) {
-    $value = $this->validate($value);
     $this->contextValue = $value;
   }
 
@@ -65,22 +66,22 @@ public function getContextDefinition() {
   }
 
   /**
-   * Implements \Drupal\Component\Plugin\Context\ContextInterface::validate().
-   *
-   * The default validation method only supports instance of checks between the
-   * contextDefintion and the contextValue. Other formats of context
-   * definitions can be supported through a subclass.
+   * Implements \Drupal\Component\Plugin\Context\ContextInterface::getConstraints().
    */
-  public function validate($value) {
-    // Check to make sure we have a class name, and that the passed context is
-    // an instance of that class name.
-    if (!empty($this->contextDefinition['class'])) {
-      if ($value instanceof $this->contextDefinition['class']) {
-        return $value;
-      }
-      throw new ContextException("The context passed was not an instance of {$this->contextDefinition['class']}.");
+  public function getConstraints() {
+    if (empty($this->contextDefinition['class'])) {
+      throw new ContextException("An error was encountered while trying to validate the context.");
     }
-    throw new ContextException("An error was encountered while trying to validate the context.");
+    return array(new Type($this->contextDefinition['class']));
+  }
+
+  /**
+   * Implements \Drupal\Component\Plugin\Context\ContextInterface::validate().
+   */
+  public function validate() {
+    $validator = Validation::createValidatorBuilder()
+      ->getValidator();
+    return $validator->validateValue($this->getContextValue(), $this->getConstraints());
   }
 
 }
diff --git a/core/lib/Drupal/Component/Plugin/Context/ContextInterface.php b/core/lib/Drupal/Component/Plugin/Context/ContextInterface.php
index 5c4373d..c5cd743 100644
--- a/core/lib/Drupal/Component/Plugin/Context/ContextInterface.php
+++ b/core/lib/Drupal/Component/Plugin/Context/ContextInterface.php
@@ -7,8 +7,6 @@
 
 namespace Drupal\Component\Plugin\Context;
 
-use Drupal\Component\Plugin\Exception\ContextException;
-
 /**
  * A generic context interface for wrapping data a plugin needs to operate.
  */
@@ -18,8 +16,9 @@
    * Sets the context value.
    *
    * @param mixed $value
-   *   The value of this context, generally an object based upon the class
-   *   matching the definition passed to setContextDefinition().
+   *   The value of this context, matching the context definition.
+   *
+   * @see \Drupal\Component\Plugin\Context\ContextInterface::setContextDefinition().
    */
   public function setContextValue($value);
 
@@ -27,42 +26,45 @@ public function setContextValue($value);
    * Gets the context value.
    *
    * @return mixed
-   *   The currently set context value within this class.
+   *   The currently set context value, or NULL if it is not set.
    */
   public function getContextValue();
 
   /**
    * Sets the definition that the context must conform to.
    *
-   * @param mixed $contextDefinition
+   * @param array $contextDefinition
    *   A defining characteristic representation of the context against which
-   *   that context can be validated. This is typically a class name, but could
-   *   be extended to support other validation notation.
+   *   that context can be validated. This is typically an array having a
+   *   class name set under the 'class' key, but it could be extended to support
+   *   other notations.
    */
   public function setContextDefinition(array $contextDefinition);
 
   /**
    * Gets the provided definition that the context must conform to.
    *
-   * @return mixed
+   * @return array
    *   The defining characteristic representation of the context.
    */
   public function getContextDefinition();
 
   /**
-   * Validate the provided context value against the provided definition.
-   *
-   * @param mixed $value
-   *   The context value that should be validated against the context
-   *   definition.
+   * Gets a list of validation constraints.
    *
-   * @return mixed
-   *   Returns the context value passed to it. If it fails validation, an
-   *   exception will be thrown.
+   * @return array
+   *   Array of constraints, each being an instance of
+   *   \Symfony\Component\Validator\Constraint.
+   */
+  public function getConstraints();
+
+  /**
+   * Validates the set context value.
    *
-   * @throws \Drupal\Component\Plugin\Exception\ContextException
-   *   If validation fails.
+   * @return \Symfony\Component\Validator\ConstraintViolationListInterface
+   *   A list of constraint violations. If the list is empty, validation
+   *   succeeded.
    */
-  public function validate($value);
+  public function validate();
 
 }
diff --git a/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php b/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php
index a628f99..457f6ec 100644
--- a/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php
+++ b/core/lib/Drupal/Component/Plugin/ContextAwarePluginBase.php
@@ -9,6 +9,8 @@
 
 use Drupal\Component\Plugin\Exception\PluginException;
 use Drupal\Component\Plugin\Context\Context;
+use Symfony\Component\Validator\ConstraintViolationList;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
 
 /**
  * Base class for plugins that are context aware.
@@ -23,22 +25,48 @@
   protected $context;
 
   /**
+   * Overrides \Drupal\Component\Plugin\PluginBase::__construct().
+   *
+   * Overrides the construction of context aware plugins to allow for
+   * unvalidated constructor based injection of contexts.
+   *
+   * @param array $configuration
+   *   The plugin configuration, i.e. an array with configuration values keyed
+   *   by configuration option name. The special key 'context' may be used to
+   *   initialize the defined contexts by setting it to an array of context
+   *   values keyed by context names.
+   */
+  public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
+    $context = array();
+    if (isset($configuration['context'])) {
+      $context = $configuration['context'];
+      unset($configuration['context']);
+    }
+    parent::__construct($configuration, $plugin_id, $discovery);
+    foreach ($context as $key => $value) {
+      $context_definition = $this->getContextDefinition($key);
+      $this->context[$key] = new Context($context_definition);
+      $this->context[$key]->setContextValue($value);
+    }
+  }
+
+  /**
    * Implements \Drupal\Component\Plugin\ContextAwarePluginInterface::getContextDefinitions().
    */
   public function getContextDefinitions() {
     $definition = $this->getDefinition();
-    return !empty($definition['context']) ? $definition['context'] : NULL;
+    return !empty($definition['context']) ? $definition['context'] : array();
   }
 
   /**
    * Implements \Drupal\Component\Plugin\ContextAwarePluginInterface::getContextDefinition().
    */
-  public function getContextDefinition($key) {
+  public function getContextDefinition($name) {
     $definition = $this->getDefinition();
-    if (empty($definition['context'][$key])) {
-      throw new PluginException("The $key context is not a valid context.");
+    if (empty($definition['context'][$name])) {
+      throw new PluginException("The $name context is not a valid context.");
     }
-    return $definition['context'][$key];
+    return $definition['context'][$name];
   }
 
   /**
@@ -46,19 +74,15 @@ public function getContextDefinition($key) {
    */
   public function getContexts() {
     $definitions = $this->getContextDefinitions();
-    // If there are no contexts defined by the plugin, return an empty array.
-    if (empty($definitions)) {
-      return array();
-    }
-    if (empty($this->context)) {
+    if ($definitions && empty($this->context)) {
       throw new PluginException("There are no set contexts.");
     }
     $contexts = array();
-    foreach (array_keys($definitions) as $key) {
-      if (empty($this->context[$key])) {
-        throw new PluginException("The $key context is not yet set.");
+    foreach (array_keys($definitions) as $name) {
+      if (empty($this->context[$name])) {
+        throw new PluginException("The $name context is not yet set.");
       }
-      $contexts[$key] = $this->context[$key];
+      $contexts[$name] = $this->context[$name];
     }
     return $contexts;
   }
@@ -66,44 +90,67 @@ public function getContexts() {
   /**
    * Implements \Drupal\Component\Plugin\ContextAwarePluginInterface::getContext().
    */
-  public function getContext($key) {
+  public function getContext($name) {
     // Check for a valid context definition.
-    $this->getContextDefinition($key);
+    $this->getContextDefinition($name);
     // Check for a valid context value.
-    if (empty($this->context[$key])) {
-      throw new PluginException("The $key context is not yet set.");
+    if (!isset($this->context[$name])) {
+      throw new PluginException("The $name context is not yet set.");
     }
 
-    return $this->context[$key];
+    return $this->context[$name];
   }
 
   /**
    * Implements \Drupal\Component\Plugin\ContextAwarePluginInterface::getContextValues().
    */
   public function getContextValues() {
-    $contexts = array();
-    foreach ($this->getContexts() as $key => $context) {
-      $contexts[$key] = $context->getContextValue();
+    $values = array();
+    foreach ($this->getContextDefinitions() as $name => $definition) {
+      $values[$name] = isset($this->context[$name]) ? $this->context[$name]->getContextValue() : NULL;
     }
-    return $contexts;
+    return $values;
   }
 
   /**
    * Implements \Drupal\Component\Plugin\ContextAwarePluginInterface::getContextValue().
    */
-  public function getContextValue($key) {
-    return $this->getContext($key)->getContextValue();
+  public function getContextValue($name) {
+    return $this->getContext($name)->getContextValue();
   }
 
   /**
    * Implements \Drupal\Component\Plugin\ContextAwarePluginInterface::setContextValue().
    */
-  public function setContextValue($key, $value) {
-    $context_definition = $this->getContextDefinition($key);
-    $this->context[$key] = new Context($context_definition);
-    $this->context[$key]->setContextValue($value);
+  public function setContextValue($name, $value) {
+    $context_definition = $this->getContextDefinition($name);
+    $this->context[$name] = new Context($context_definition);
+    $this->context[$name]->setContextValue($value);
 
+    // Verify the provided value validates.
+    $violations = $this->context[$name]->validate();
+    if (count($violations) > 0) {
+      throw new PluginException("The provided context value does not pass validation.");
+    }
     return $this;
   }
 
+  /**
+   * Implements \Drupal\Component\Plugin\ContextAwarePluginInterface::valdidateContexts().
+   */
+  public function validateContexts() {
+    $violations = new ConstraintViolationList();
+    // @todo: Implement symfony validator API to let the validator traverse
+    // and set property paths accordingly.
+
+    foreach ($this->getContextDefinitions() as $name => $definition) {
+      // Validate any set values.
+      if (isset($this->context[$name])) {
+        $violations->addAll($this->context[$name]->validate());
+      }
+      // @todo: If no value is set, make sure any mapping is validated.
+    }
+    return $violations;
+  }
+
 }
diff --git a/core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php b/core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php
index 68d8012..2d1aa8a 100644
--- a/core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php
+++ b/core/lib/Drupal/Component/Plugin/ContextAwarePluginInterface.php
@@ -8,35 +8,43 @@
 namespace Drupal\Component\Plugin;
 
 use Drupal\Component\Plugin\Exception\PluginException;
-use Drupal\Component\Plugin\Context\Context;
 
 /**
  * Interface for defining context aware plugins.
+ *
+ * Context aware plugins can specify an array of context definitions keyed by
+ * context name at the plugin definition under the "context" key.
  */
 interface ContextAwarePluginInterface extends PluginInspectionInterface {
 
   /**
    * Gets the context definitions of the plugin.
    *
-   * @return array|null
-   *   The context definitions if set, otherwise NULL.
+   * @return array
+   *   The array of context definitions, keyed by context name.
    */
   public function getContextDefinitions();
 
   /**
-   * Gets the a specific context definition of the plugin.
+   * Gets a specific context definition of the plugin.
    *
-   * @param string $key
+   * @param string $name
    *   The name of the context in the plugin definition.
    *
-   * @return mixed
+   * @throws \Drupal\Component\Plugin\Exception\PluginException
+   *   If the requested context is not defined.
+   *
+   * @return array
    *   The definition against which the context value must validate.
    */
-  public function getContextDefinition($key);
+  public function getContextDefinition($name);
 
   /**
    * Gets the defined contexts.
    *
+   * @throws \Drupal\Component\Plugin\Exception\PluginException
+   *   If contexts are defined but not set.
+   *
    * @return array
    *   The set context objects.
    */
@@ -45,47 +53,64 @@ public function getContexts();
   /**
    * Gets a defined context.
    *
-   * @param string $key
-   *   The name of the context in the plugin configuration. This string is
-   *   usually identical to the representative string in the plugin definition.
+   * @param string $name
+   *   The name of the context in the plugin definition.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\PluginException
+   *   If the requested context is not set.
    *
    * @return \Drupal\Component\Plugin\Context\ContextInterface
    *   The context object.
    */
-  public function getContext($key);
+  public function getContext($name);
 
   /**
    * Gets the values for all defined contexts.
    *
    * @return array
-   *   The set context object values.
+   *   An array of set context values, keyed by context name. If a context is
+   *   unset its value is returned as NULL.
    */
   public function getContextValues();
 
   /**
    * Gets the value for a defined context.
    *
-   * @param string $key
-   *   The name of the context in the plugin configuration. This string is
-   *   usually identical to the representative string in the plugin definition.
+   * @param string $name
+   *   The name of the context in the plugin configuration.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\PluginException
+   *   If the requested context is not set.
    *
    * @return mixed
    *   The currently set context value.
    */
-  public function getContextValue($key);
+  public function getContextValue($name);
 
   /**
    * Sets the value for a defined context.
    *
-   * @param string $key
+   * @param string $name
    *   The name of the context in the plugin definition.
    * @param mixed $value
-   *   The variable to set the context to. This should validate against the
+   *   The value to set the context to. The value has to validate against the
    *   provided context definition.
    *
+   * @throws \Drupal\Component\Plugin\Exception\PluginException
+   *   If the value does not pass validation.
+   *
    * @return \Drupal\Component\Plugin\ContextAwarePluginInterface.
    *   A context aware plugin object for chaining.
    */
-  public function setContextValue($key, $value);
+  public function setContextValue($name, $value);
+
+  /**
+   * Validates the set values for the defined contexts.
+   *
+   * @return \Symfony\Component\Validator\ConstraintViolationListInterface
+   *   A list of constraint violations. If the list is empty, validation
+   *   succeeded.
+   */
+  public function validateContexts();
 
 }
diff --git a/core/lib/Drupal/Core/Condition/ConditionInterface.php b/core/lib/Drupal/Core/Condition/ConditionInterface.php
new file mode 100644
index 0000000..00538ba
--- /dev/null
+++ b/core/lib/Drupal/Core/Condition/ConditionInterface.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Condition\ConditionInterface.
+ */
+
+namespace Drupal\Core\Condition;
+
+use Drupal\Core\Executable\ExecutableInterface;
+
+/**
+ * An interface for condition plugins.
+ *
+ * @see \Drupal\Core\Executable\ExecutableInterface
+ */
+interface ConditionInterface extends ExecutableInterface {
+
+  /**
+   * Determines whether condition result will be negated.
+   *
+   * @return boolean
+   *   Whether the condition result will be negated.
+   */
+  public function isNegated();
+
+  /**
+   * Evaluates the condition and returns TRUE or FALSE accordingly.
+   *
+   * @return bool
+   *   TRUE if the condition has been met, FALSE otherwise.
+   */
+  public function evaluate();
+
+}
diff --git a/core/lib/Drupal/Core/Condition/ConditionManager.php b/core/lib/Drupal/Core/Condition/ConditionManager.php
new file mode 100644
index 0000000..c7cdb60
--- /dev/null
+++ b/core/lib/Drupal/Core/Condition/ConditionManager.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Condition\ConditionManager.
+ */
+
+namespace Drupal\Core\Condition;
+
+use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Core\Executable\ExecutableManagerInterface;
+use Drupal\Core\Executable\ExecutableInterface;
+use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
+use Drupal\Core\Plugin\Discovery\AlterDecorator;
+use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Core\Plugin\Discovery\CacheDecorator;
+
+/**
+ * A plugin manager for condition plugins.
+ */
+class ConditionManager extends PluginManagerBase implements ExecutableManagerInterface {
+
+  /**
+   * Constructs aa ConditionManager object.
+   */
+  public function __construct() {
+    $this->discovery = new AnnotatedClassDiscovery('Core', 'Condition');
+    $this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
+    $this->discovery = new AlterDecorator($this->discovery, 'condition_info');
+    $this->discovery = new CacheDecorator($this->discovery, 'condition:' . language(LANGUAGE_TYPE_INTERFACE)->langcode);
+
+    $this->factory = new DefaultFactory($this);
+  }
+
+  /**
+   * Override of Drupal\Component\Plugin\PluginManagerBase::createInstance().
+   */
+  public function createInstance($plugin_id, array $configuration = array()) {
+    $plugin = $this->factory->createInstance($plugin_id, $configuration);
+    return $plugin->setExecutableManager($this);
+  }
+
+  /**
+   * Implements Drupal\Core\Executable\ExecutableManagerInterface::execute().
+   */
+  public function execute(ExecutableInterface $condition) {
+    $result = $condition->evaluate();
+    return $condition->isNegated() ? !$result : $result;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Condition/ConditionPluginBase.php b/core/lib/Drupal/Core/Condition/ConditionPluginBase.php
new file mode 100644
index 0000000..2bd7910
--- /dev/null
+++ b/core/lib/Drupal/Core/Condition/ConditionPluginBase.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Condition\ConditionPluginBase.
+ */
+
+namespace Drupal\Core\Condition;
+
+use Drupal\Core\Executable\ExecutablePluginBase;
+
+/**
+ * Provides a basis for fulfilling contexts for condition plugins.
+ */
+abstract class ConditionPluginBase extends ExecutablePluginBase implements ConditionInterface {
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::getFormID().
+   */
+  public function getFormID() {
+    $definition = $this->getDefinition();
+    return implode('_', array($definition['module'], $definition['id'], 'condition'));
+  }
+
+  /**
+   * Implements \Drupal\condition\Plugin\ConditionInterface::isNegated().
+   */
+  public function isNegated() {
+    return !empty($this->configuration['negate']);
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   */
+  public function buildForm(array $form, array &$form_state) {
+    $form['negate'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Negate the condition.'),
+      '#default_value' => isset($this->configuration['negate']) ? $this->configuration['negate'] : FALSE,
+    );
+    return $form;
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::validateForm().
+   */
+  public function validateForm(array &$form, array &$form_state) {}
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    $this->configuration['negate'] = $form_state['values']['negate'];
+  }
+
+  /**
+   * Implements \Drupal\Core\Executable\ExecutablePluginBase::execute().
+   */
+  public function execute() {
+    return $this->executableManager->execute($this);
+  }
+
+}
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 035f282..a91106b 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -270,6 +270,8 @@ public function build(ContainerBuilder $container) {
     $container->register('flood', 'Drupal\Core\Flood\DatabaseBackend')
       ->addArgument(new Reference('database'));
 
+    $container->register('plugin.manager.condition', 'Drupal\Core\Condition\ConditionManager');
+
     $container->addCompilerPass(new RegisterMatchersPass());
     $container->addCompilerPass(new RegisterRouteFiltersPass());
     // Add a compiler pass for registering event subscribers.
diff --git a/core/lib/Drupal/Core/Executable/ExecutableException.php b/core/lib/Drupal/Core/Executable/ExecutableException.php
new file mode 100644
index 0000000..ae9b135
--- /dev/null
+++ b/core/lib/Drupal/Core/Executable/ExecutableException.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * @file
+ * Definition of \Drupal\Core\Executable\ExecutableException.
+ */
+
+namespace Drupal\Core\Executable;
+
+use Exception;
+use Drupal\Component\Plugin\Exception\ExceptionInterface;
+
+/**
+ * Generic executable plugin exception class.
+ */
+class ExecutableException extends Exception implements ExceptionInterface {
+}
diff --git a/core/lib/Drupal/Core/Executable/ExecutableInterface.php b/core/lib/Drupal/Core/Executable/ExecutableInterface.php
new file mode 100644
index 0000000..f6f5fed
--- /dev/null
+++ b/core/lib/Drupal/Core/Executable/ExecutableInterface.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Executable\ExecutableInterface.
+ */
+
+namespace Drupal\Core\Executable;
+
+use Drupal\Component\Plugin\ContextAwarePluginInterface;
+use Drupal\Core\Form\FormInterface;
+
+/**
+ * An interface for executable plugins.
+ *
+ * Executable plugins are context-aware and configurable. They support the
+ * following keys in their plugin definitions:
+ * - context: An array of context definitions, keyed by context name. Each
+ *   context definition is a typed data definition describing the context. Check
+ *   the typed data definition docs for details.
+ * - configuration: An array of configuration option definitions, keyed by
+ *   option name. Each option definition is a typed data definition describing
+ *   the configuration option. Check the typed data definition docs for details.
+ *
+ * @see \Drupal\Core\TypedData\TypedDataManager::create()
+ */
+interface ExecutableInterface extends ContextAwarePluginInterface, FormInterface {
+
+  /**
+   * Executes the plugin.
+   */
+  public function execute();
+
+  /**
+   * Provides a human readable summary of the executable's configuration.
+   */
+  public function summary();
+
+  /**
+   * Sets the executable manager class.
+   *
+   * @param \Drupal\Core\Condition\ConditionManager $executableManager
+   *   The executable manager.
+   */
+  public function setExecutableManager(ExecutableManagerInterface $executableManager);
+
+}
diff --git a/core/lib/Drupal/Core/Executable/ExecutableManagerInterface.php b/core/lib/Drupal/Core/Executable/ExecutableManagerInterface.php
new file mode 100644
index 0000000..c715f7d
--- /dev/null
+++ b/core/lib/Drupal/Core/Executable/ExecutableManagerInterface.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Executable\ExecutableManagerInterface.
+ */
+
+namespace Drupal\Core\Executable;
+
+use Drupal\Component\Plugin\PluginManagerInterface;
+
+/**
+ * An interface for managers of executable plugins.
+ */
+interface ExecutableManagerInterface extends PluginManagerInterface {
+
+  /**
+   * Executes an executable plugin.
+   *
+   * @param \Drupal\Core\Executable\ExecutableInterface $plugin
+   *   An executable plugin instance managed by the implementing manager.
+   *
+   * @throws \Drupal\Core\Executable\ExecutableException
+   *   If the plugin could not be executed.
+   *
+   * @return mixed
+   *   The returned data varies by plugin implementation, e.g. conditions return
+   *   the the boolean evaluation result.
+   */
+  public function execute(ExecutableInterface $plugin);
+
+}
diff --git a/core/lib/Drupal/Core/Executable/ExecutablePluginBase.php b/core/lib/Drupal/Core/Executable/ExecutablePluginBase.php
new file mode 100644
index 0000000..426e8b8
--- /dev/null
+++ b/core/lib/Drupal/Core/Executable/ExecutablePluginBase.php
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Executable\ExecutablePluginBase.
+ */
+
+namespace Drupal\Core\Executable;
+
+use Drupal\Core\Plugin\ContextAwarePluginBase;
+use Symfony\Component\Validator\Validation;
+use Drupal\Component\Plugin\Exception\PluginException;
+
+/**
+ * Provides the basic architecture for executable plugins.
+ */
+abstract class ExecutablePluginBase extends ContextAwarePluginBase implements ExecutableInterface {
+
+  /**
+   * The condition manager to proxy execute calls through.
+   *
+   * @var \Drupal\Component\Plugin\PluginManagerInterface
+   */
+  protected $executableManager;
+
+  /**
+   * Implements \Drupal\Core\Executable\ExecutableInterace::setExecutableManager().
+   */
+  public function setExecutableManager(ExecutableManagerInterface $executableManager) {
+    $this->executableManager = $executableManager;
+    return $this;
+  }
+
+  /**
+   * Gets an array of definitions of available configuration options.
+   *
+   * @todo: This needs to go into an interface.
+   *
+   * @return array
+   *   An array of typed data definitions describing available configuration
+   *   options, keyed by option name.
+   */
+  public function getConfigDefinitions() {
+    $definition = $this->getDefinition();
+    if (!empty($definition['configuration'])) {
+      return $definition['configuration'];
+    }
+    return array();
+  }
+
+  /**
+   * Gets the definition of a configuration option.
+   *
+   * @todo: This needs to go into an interface.
+   *
+   * @return array
+   *   The typed data definition describing the configuration option, or FALSE
+   *   if the option does not exist.
+   */
+  public function getConfigDefinition($key) {
+    $definition = $this->getDefinition();
+    if (!empty($definition['configuration'][$key])) {
+      return $definition['configuration'][$key];
+    }
+    return FALSE;
+  }
+
+  /**
+   * Gets all configuration values.
+   *
+   * @todo: This needs to go into an interface.
+   *
+   * @return array
+   *   The array of all configuration values, keyed by configuration option
+   *   name.
+   */
+  public function getConfig() {
+    return $this->configuration;
+  }
+
+  /**
+   * Sets the value of a particular configuration option.
+   *
+   * @param string $name
+   *   The name of the configuration option to set.
+   * @param mixed $value
+   *   The value to set.
+   *
+   * @todo This doesn't belong here. Move this into a new base class in
+   *   http://drupal.org/node/1764380.
+   * @todo This does not set a value in config(), so the name is confusing.
+   *
+   * @return \Drupal\Core\Executable\ExecutablePluginBase.
+   *   The executable object for chaining.
+   */
+  public function setConfig($key, $value) {
+    if ($definition = $this->getConfigDefinition($key)) {
+      $typed_data = typed_data()->create($definition, $value);
+
+      if ($typed_data->validate()->count() > 0) {
+        throw new PluginException("The provided configuration value does not pass validation.");
+      }
+    }
+    $this->configuration[$key] = $value;
+    return $this;
+  }
+}
+
diff --git a/core/lib/Drupal/Core/Plugin/Context/Context.php b/core/lib/Drupal/Core/Plugin/Context/Context.php
index bcab7e1..e6d680f 100644
--- a/core/lib/Drupal/Core/Plugin/Context/Context.php
+++ b/core/lib/Drupal/Core/Plugin/Context/Context.php
@@ -8,9 +8,11 @@
 namespace Drupal\Core\Plugin\Context;
 
 use Drupal\Component\Plugin\Context\Context as ComponentContext;
-use Drupal\Component\Plugin\Exception\ContextException;
-use Drupal\Core\TypedData\TypedDataManager;
+use Drupal\Core\TypedData\ComplexDataInterface;
+use Drupal\Core\TypedData\ListInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
+use Drupal\Core\Validation\DrupalTranslator;
+use Symfony\Component\Validator\Validation;
 
 /**
  * A Drupal specific context wrapper class.
@@ -26,18 +28,32 @@ class Context extends ComponentContext {
    */
   public function getContextValue() {
     $typed_value = parent::getContextValue();
-    // If the data is of a primitive type, directly return the plain value.
-    // That way, e.g. a string will be return as plain PHP string.
-    if ($typed_value instanceof \Drupal\Core\TypedData\TypedDataInterface) {
-      $type_definition = typed_data()->getDefinition($typed_value->getType());
-      if (!empty($type_definition['primitive type'])) {
-        return $typed_value->getValue();
-      }
+    // If the typed data is complex, pass it on as typed data. Else pass on its
+    // plain value, such that e.g. a string will be directly returned as PHP
+    // string.
+    $is_complex = $typed_value instanceof ComplexDataInterface;
+    if (!$is_complex && $typed_value instanceof ListInterface) {
+      $is_complex = $typed_value[0] instanceof ComplexDataInterface;
+    }
+    // @todo We won't need the getType == entity check once #1868004 lands.
+    if ($typed_value instanceof TypedDataInterface && (!$is_complex || $typed_value->getType() == 'entity')) {
+      return $typed_value->getValue();
     }
     return $typed_value;
   }
 
   /**
+   * Implements \Drupal\Component\Plugin\Context\ContextInterface::setContextValue().
+   */
+  public function setContextValue($value) {
+    // Make sure the value set is a typed data object.
+    if (!empty($this->contextDefinition['type']) && !$value instanceof TypedDataInterface) {
+      $value = typed_data()->create($this->contextDefinition, $value);
+    }
+    parent::setContextValue($value);
+  }
+
+  /**
    * Gets the context value as typed data object.
    *
    * parent::getContextValue() does not do all the processing required to
@@ -54,21 +70,31 @@ public function getTypedContext() {
   }
 
   /**
-   * Override for \Drupal\Component\Plugin\Context\Context::validate().
+   * Implements \Drupal\Component\Plugin\Context\ContextInterface::getConstraints().
    */
-  public function validate($value) {
+  public function getConstraints() {
     if (!empty($this->contextDefinition['type'])) {
-      $typed_data_manager = new TypedDataManager();
-      $typed_data = $typed_data_manager->create($this->contextDefinition, $value);
-      // If we do have a typed data definition, validate it and return the
-      // typed data instance instead.
-      $violations = $typed_data->validate();
-      if (count($violations) == 0) {
-        return $typed_data;
-      }
-      throw new ContextException("The context passed could not be validated through typed data.");
+      // If we do have typed data, leverage it for getting constraints.
+      return $this->getTypedContext()->getConstraints();
     }
-    return parent::validate($value);
+    return parent::getConstraints();
   }
 
+  /**
+   * Overrides \Drupal\Component\Plugin\Context\Context::getConstraints().
+   */
+  public function validate() {
+    $validator = Validation::createValidatorBuilder()
+      ->setTranslator(new DrupalTranslator())
+      ->getValidator();
+
+    // @todo We won't need to special case "entity" here once #1868004 lands.
+    if (!empty($this->contextDefinition['type']) && $this->contextDefinition['type'] == 'entity') {
+      $value = $this->getTypedContext();
+    }
+    else {
+      $value = $this->getContextValue();
+    }
+    return $validator->validateValue($value, $this->getConstraints());
+  }
 }
diff --git a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php
index 028befd..45648d4 100644
--- a/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php
+++ b/core/lib/Drupal/Core/Plugin/ContextAwarePluginBase.php
@@ -8,7 +8,9 @@
 namespace Drupal\Core\Plugin;
 
 use Drupal\Component\Plugin\ContextAwarePluginBase as PluginBase;
+use Drupal\Component\Plugin\Exception\PluginException;
 use Drupal\Core\Plugin\Context\Context;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
 
 /**
  * Drupal specific class for plugins that use context.
@@ -20,13 +22,35 @@
 abstract class ContextAwarePluginBase extends PluginBase {
 
   /**
+   * Override of \Drupal\Component\Plugin\ContextAwarePluginBase::__construct().
+   */
+  public function __construct(array $configuration, $plugin_id, DiscoveryInterface $discovery) {
+    $context = array();
+    if (isset($configuration['context'])) {
+      $context = $configuration['context'];
+      unset($configuration['context']);
+    }
+    parent::__construct($configuration, $plugin_id, $discovery);
+    foreach ($context as $key => $value) {
+      $context_definition = $this->getContextDefinition($key);
+      $this->context[$key] = new Context($context_definition);
+      $this->context[$key]->setContextValue($value);
+    }
+  }
+
+  /**
    * Override of \Drupal\Component\Plugin\ContextAwarePluginBase::setContextValue().
    */
-  public function setContextValue($key, $value) {
-    $context_definition = $this->getContextDefinition($key);
-    $this->context[$key] = new Context($context_definition);
-    $this->context[$key]->setContextValue($value);
+  public function setContextValue($name, $value) {
+    $context_definition = $this->getContextDefinition($name);
+    // Use the Drupal specific context class.
+    $this->context[$name] = new Context($context_definition);
+    $this->context[$name]->setContextValue($value);
 
+    // Verify the provided value validates.
+    if ($this->context[$name]->validate()->count() > 0) {
+      throw new PluginException("The provided context value does not pass validation.");
+    }
     return $this;
   }
 
diff --git a/core/lib/Drupal/Core/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php b/core/lib/Drupal/Core/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php
index 21b2ac2..1e1aba4 100644
--- a/core/lib/Drupal/Core/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php
+++ b/core/lib/Drupal/Core/Plugin/Validation/Constraint/EntityTypeConstraintValidator.php
@@ -22,7 +22,7 @@ public function validate($typed_data, Constraint $constraint) {
     $entity = isset($typed_data) ? $typed_data->getValue() : FALSE;
 
     if (!empty($entity) && $entity->entityType() != $constraint->type) {
-      $this->context->addViolation($constraint->message, array('%type', $constraint->type));
+      $this->context->addViolation($constraint->message, array('%type' => $constraint->type));
     }
   }
 }
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Condition/NodeType.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Condition/NodeType.php
new file mode 100644
index 0000000..f6d0b22
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Condition/NodeType.php
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\Plugin\Core\Condition\NodeType.
+ */
+
+namespace Drupal\node\Plugin\Core\Condition;
+
+use Drupal\Core\Condition\ConditionPluginBase;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Provides a 'Node Type' condition.
+ *
+ * @Plugin(
+ *   id = "node_type",
+ *   label = @Translation("Node Bundle"),
+ *   module = "node",
+ *   context = {
+ *     "node" = {
+ *       "type" = "entity",
+ *       "constraints" = {
+ *         "EntityType" = "node"
+ *       }
+ *     }
+ *   }
+ * )
+ */
+class NodeType extends ConditionPluginBase {
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   */
+  public function buildForm(array $form, array &$form_state) {
+    $form = parent::buildForm($form, $form_state);
+    $options = array();
+    foreach (node_type_get_types() as $type) {
+      $options[$type->type] = $type->name;
+    }
+    $form['bundles'] = array(
+      '#type' => 'checkboxes',
+      '#options' => $options,
+      '#required' => TRUE,
+      '#default_value' => isset($this->configuration['bundles']) ? $this->configuration['bundles'] : array(),
+    );
+    return $form;
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::validateForm().
+   */
+  public function validateForm(array &$form, array &$form_state) {
+    foreach ($form_state['values']['bundles'] as $bundle) {
+      if (!in_array($bundle, array_keys(node_type_get_types()))) {
+        form_set_error('bundles', t('You have chosen an invalid node bundle, please check your selection and try again.'));
+      }
+    }
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    $this->configuration['bundles'] = $form_state['values']['bundles'];
+    parent::submitForm($form, $form_state);
+  }
+
+  /**
+   * Implements \Drupal\Core\Executable\ExecutableInterface::summary().
+   */
+  public function summary() {
+    if (count($this->configuration['bundles']) > 1) {
+      $bundles = $this->configuration['bundles'];
+      $last = array_pop($bundles);
+      $bundles = implode(', ', $bundles);
+      return t('The node bundle is @bundles or @last', array('@bundles' => $bundles, '@last' => $last));
+    }
+    $bundle = $this->configuration['bundles'][0];
+    return t('The node bundle is @bundle', array('@bundle' => $bundle));
+  }
+
+  /**
+   * Implements \Drupal\condition\ConditionInterface::evaluate().
+   */
+  public function evaluate() {
+    $node = $this->getContextValue('node');
+    return in_array($node->type, $this->configuration['bundles']);
+  }
+
+}
diff --git a/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php b/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php
new file mode 100644
index 0000000..addc5c0
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\condition\Tests\Condition\NodeConditionTest.
+ */
+
+namespace Drupal\node\Tests\Condition;
+
+use Drupal\simpletest\DrupalUnitTestBase;
+use Drupal\Core\Condition\ConditionManager;
+
+/**
+ * Tests the node conditions.
+ */
+class NodeConditionTest extends DrupalUnitTestBase {
+
+  public static $modules = array('system', 'node', 'field');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Node Condition Plugins',
+      'description' => 'Tests that conditions, provided by the node module, are working properly.',
+      'group' => 'Condition API',
+    );
+  }
+
+  protected function setUp() {
+    parent::setUp();
+    $this->installSchema('node', 'node_type');
+    $this->installSchema('node', 'node');
+    $this->installSchema('node', 'node_revision');
+    $this->installSchema('field', 'field_config');
+    $this->installSchema('field', 'field_config_instance');
+  }
+
+  /**
+   * Tests conditions.
+   */
+  function testConditions() {
+    $manager = new ConditionManager();
+
+    // Get some nodes of various types to check against.
+    $page = entity_create('node', array('type' => 'page', 'title' => $this->randomName()));
+    $page->save();
+    $article = entity_create('node', array('type' => 'article', 'title' => $this->randomName()));
+    $article->save();
+    $test = entity_create('node', array('type' => 'test', 'title' => $this->randomName()));
+    $test->save();
+
+    // Grab the node type condition and configure it to check against node type
+    // of 'article' and set the context to the page type node.
+    $condition = $manager->createInstance('node_type')
+      ->setConfig('bundles', array('article'))
+      ->setContextValue('node', $page);
+    $this->assertFalse($condition->execute(), 'Page type nodes fail node type checks for articles.');
+    // Check for the proper summary.
+    $this->assertEqual('The node bundle is article', $condition->summary());
+
+    // Set the node type check to page.
+    $condition->setConfig('bundles', array('page'));
+    $this->assertTrue($condition->execute(), 'Page type nodes pass node type checks for pages');
+    // Check for the proper summary.
+    $this->assertEqual('The node bundle is page', $condition->summary());
+
+    // Set the node type check to page or article.
+    $condition->setConfig('bundles', array('page', 'article'));
+    $this->assertTrue($condition->execute(), 'Page type nodes pass node type checks for pages or articles');
+    // Check for the proper summary.
+    $this->assertEqual('The node bundle is page or article', $condition->summary());
+
+    // Set the context to the article node.
+    $condition->setContextValue('node', $article);
+    $this->assertTrue($condition->execute(), 'Article type nodes pass node type checks for pages or articles');
+
+    // Set the context to the test node.
+    $condition->setContextValue('node', $test);
+    $this->assertFalse($condition->execute(), 'Test type nodes pass node type checks for pages or articles');
+
+    // Check a greater than 2 bundles summary scenario.
+    $condition->setConfig('bundles', array('page', 'article', 'test'));
+    $this->assertEqual('The node bundle is page, article or test', $condition->summary());
+
+    // Test Constructor injection.
+    $condition = $manager->createInstance('node_type', array('bundles' => array('article'), 'context' => array('node' => $article)));
+    $this->assertTrue($condition->execute(), 'Constructor injection of context and configuration working as anticipated.');
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Condition/ConditionFormTest.php b/core/modules/system/lib/Drupal/system/Tests/Condition/ConditionFormTest.php
new file mode 100644
index 0000000..e191efe
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Condition/ConditionFormTest.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Condition\ConditionFormTest.
+ */
+
+namespace Drupal\system\Tests\Condition;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests condition forms, configuration and execution.
+ *
+ * Checks condition forms and submission and gives a very cursory check to make
+ * sure the configuration that was submitted actually causes the condition to
+ * validate correctly.
+ */
+class ConditionFormTest extends WebTestBase {
+
+  public static $modules = array('node', 'condition_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Condition Form Tests',
+      'description' => 'Tests that condtion plugins basic form handling is working.',
+      'group' => 'Condition API',
+    );
+  }
+
+  /**
+   * Submit the condition_node_type_test_form to test condition forms.
+   */
+  function testConfigForm() {
+    $article = entity_create('node', array('type' => 'article', 'title' => $this->randomName()));
+    $article->save();
+    $this->drupalGet('condition_test');
+    $this->assertField('bundles[article]', 'There is an article bundle selector.');
+    $this->assertField('bundles[page]', 'There is a page bundle selector.');
+    $this->drupalPost(NULL, array('bundles[page]' => 'page', 'bundles[article]' => 'article'), t('Submit'));
+    $this->assertText('The bundles are article and page', 'The form component appropriately saved the bundles.');
+    $this->assertText('Executed successfully.', 'The form configured condition executed properly.');
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
index 888f1e6..c22f222 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
@@ -93,8 +93,8 @@ function testContext() {
       $plugin->setContextValue('user', $node);
       $this->fail('The node context should fail validation for a user context.');
     }
-    catch (ContextException $e) {
-      $this->assertEqual($e->getMessage(), 'The context passed was not an instance of Drupal\user\Plugin\Core\Entity\User.');
+    catch (PluginException $e) {
+      $this->assertEqual($e->getMessage(), 'The provided context value does not pass validation.');
     }
 
     // Set an appropriate context value appropriately and check to make sure
@@ -157,13 +157,8 @@ function testContext() {
     }
 
     // With no contexts set, try to get the context values.
-    try {
-      $complex_plugin->getContextValues();
-      $this->fail('There should not be any contexts set yet.');
-    }
-    catch (PluginException $e) {
-      $this->assertEqual($e->getMessage(), 'There are no set contexts.');
-    }
+    $values = $complex_plugin->getContextValues();
+    $this->assertIdentical(array_filter($values), array(), 'There are no set contexts.');
 
     // Set the user context value.
     $complex_plugin->setContextValue('user', $user);
@@ -178,13 +173,9 @@ function testContext() {
     }
 
     // With only the user context set, try to get the context values.
-    try {
-      $complex_plugin->getContextValues();
-      $this->fail('The node context should not yet be set.');
-    }
-    catch (PluginException $e) {
-      $this->assertEqual($e->getMessage(), 'The node context is not yet set.');
-    }
+    $values = $complex_plugin->getContextValues();
+    $this->assertNull($values['node'], 'The node context is not yet set.');
+    $this->assertNotNull($values['user'], 'The user context is set');
 
     $complex_plugin->setContextValue('node', $node);
     $context_wrappers = $complex_plugin->getContexts();
diff --git a/core/modules/system/tests/modules/condition_test/condition_test.info b/core/modules/system/tests/modules/condition_test/condition_test.info
new file mode 100644
index 0000000..753f032
--- /dev/null
+++ b/core/modules/system/tests/modules/condition_test/condition_test.info
@@ -0,0 +1,6 @@
+name = "Condition Test Support"
+description = "Test general form component for condition plugins."
+package = Testing
+version = VERSION
+core = 8.x
+hidden = TRUE
diff --git a/core/modules/system/tests/modules/condition_test/condition_test.module b/core/modules/system/tests/modules/condition_test/condition_test.module
new file mode 100644
index 0000000..1310b21
--- /dev/null
+++ b/core/modules/system/tests/modules/condition_test/condition_test.module
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * Implements hook_node_info().
+ */
+function condition_test_node_info() {
+  return array(
+    'article' => array(
+      'name' => t('Article'),
+      'base' => 'article',
+      'description' => t('An article content type'),
+      'title_label' => t('Subject'),
+    ),
+    'page' => array(
+      'name' => t('Page'),
+      'base' => 'page',
+      'description' => t('A page content type'),
+      'title_label' => t('Subject'),
+    ),
+  );
+}
diff --git a/core/modules/system/tests/modules/condition_test/condition_test.routing.yml b/core/modules/system/tests/modules/condition_test/condition_test.routing.yml
new file mode 100644
index 0000000..96fbdca
--- /dev/null
+++ b/core/modules/system/tests/modules/condition_test/condition_test.routing.yml
@@ -0,0 +1,6 @@
+condition_test_1:
+  pattern: '/condition_test'
+  defaults:
+    _controller: '\Drupal\condition_test\FormController::getForm'
+  requirements:
+    _access: 'TRUE'
diff --git a/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php b/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php
new file mode 100644
index 0000000..35a5325
--- /dev/null
+++ b/core/modules/system/tests/modules/condition_test/lib/Drupal/condition_test/FormController.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\condition_test\FormController.
+ */
+
+namespace Drupal\condition_test;
+
+use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Condition\ConditionManager;
+
+/**
+ * Routing controller class for condition_test testing of condition forms.
+ */
+class FormController implements FormInterface {
+
+  /**
+   * The condition plugin we will be working with.
+   *
+   * @var \Drupal\Core\Condition\ConditionInterface
+   */
+  protected $condition;
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::getFormID().
+   */
+  public function getFormID() {
+    return 'condition_node_type_test_form';
+  }
+
+  /**
+   * Provides a simple method the router can fire in order to invoke this form.
+   */
+  public function getForm() {
+    $manager = new ConditionManager();
+    $this->condition = $manager->createInstance('node_type');
+    return drupal_get_form($this);
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::buildForm().
+   */
+  public function buildForm(array $form, array &$form_state) {
+    $form = $this->condition->buildForm($form, $form_state);
+    $form['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Submit'),
+    );
+    return $form;
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::validateForm().
+   */
+  public function validateForm(array &$form, array &$form_state) {
+    $this->condition->validateForm($form, $form_state);
+  }
+
+  /**
+   * Implements \Drupal\Core\Form\FormInterface::submitForm().
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    $this->condition->submitForm($form, $form_state);
+    $config = $this->condition->getConfig();
+    $bundles = implode(' and ', $config['bundles']);
+    drupal_set_message(t('The bundles are @bundles', array('@bundles' => $bundles)));
+    $article = node_load(1);
+    $this->condition->setContextValue('node', $article);
+    if ($this->condition->execute()) {
+      drupal_set_message(t('Executed successfully.'));
+    }
+  }
+}
