diff --git a/core/lib/Drupal/Core/Action/ActionBase.php b/core/lib/Drupal/Core/Action/ActionBase.php
index 89e184a..150af60 100644
--- a/core/lib/Drupal/Core/Action/ActionBase.php
+++ b/core/lib/Drupal/Core/Action/ActionBase.php
@@ -7,8 +7,8 @@
 
 namespace Drupal\Core\Action;
 
-use Drupal\Core\Plugin\PluginBase;
 use Drupal\Core\Action\ActionInterface;
+use Drupal\Core\Executable\ExecutablePluginBase;
 
 /**
  * Provides a base implementation for an Action plugin.
@@ -18,14 +18,15 @@
  * @see \Drupal\Core\Action\ActionInterface
  * @see plugin_api
  */
-abstract class ActionBase extends PluginBase implements ActionInterface {
+abstract class ActionBase extends ExecutablePluginBase implements ActionInterface {
 
   /**
    * {@inheritdoc}
    */
-  public function executeMultiple(array $entities) {
-    foreach ($entities as $entity) {
-      $this->execute($entity);
+  public function executeMultiple($context_name, array $context_values) {
+    foreach ($context_values as $context_value) {
+      $this->setContextValue($context_name, $context_value);
+      $this->execute();
     }
   }
 
diff --git a/core/lib/Drupal/Core/Action/ActionInterface.php b/core/lib/Drupal/Core/Action/ActionInterface.php
index fe04acb..867ed80 100644
--- a/core/lib/Drupal/Core/Action/ActionInterface.php
+++ b/core/lib/Drupal/Core/Action/ActionInterface.php
@@ -13,13 +13,19 @@
 /**
  * Provides an interface for an Action plugin.
  *
+ * Action 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 describes the data type and other properties of the
+ *   context. Check the context 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.
+ *
  * @todo WARNING: The action API is going to receive some additions before
  * release. The following additions are likely to happen:
  *  - The way configuration is handled and configuration forms are built is
  *    likely to change in order for the plugin to be of use for Rules.
- *  - Actions are going to become context-aware in
- *    https://drupal.org/node/2011038, what will deprecated the 'type'
- *    annotation.
  *  - Instead of action implementations saving entities, support for marking
  *    required context as to be saved by the execution manager will be added as
  *    part of https://www.drupal.org/node/2347017.
@@ -37,11 +43,19 @@
 interface ActionInterface extends ExecutableInterface, PluginInspectionInterface {
 
   /**
-   * Executes the plugin for an array of objects.
+   * Executes the action for multiple context values.
+   *
+   * This method can be used for executing the action multiple times,
+   * while allowing the action implementation to perform optimizations.
+   * If the implementation provides no optimizations, the fallback behaviour
+   * is to execute the action once per value.
    *
-   * @param array $objects
-   *   An array of entities.
+   * @param string $context_name
+   *   The name of the context with multiple values.
+   * @param array $context_values
+   *   An array of context values, for which the action will be executed once
+   *   per value.
    */
-  public function executeMultiple(array $objects);
+  public function executeMultiple($context_name, array $context_values);
 
 }
diff --git a/core/lib/Drupal/Core/Action/ActionManager.php b/core/lib/Drupal/Core/Action/ActionManager.php
index 1baf427..58b2c51 100644
--- a/core/lib/Drupal/Core/Action/ActionManager.php
+++ b/core/lib/Drupal/Core/Action/ActionManager.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\Context\ContextAwarePluginManagerTrait;
 use Drupal\Core\Plugin\DefaultPluginManager;
 
 /**
@@ -21,6 +22,8 @@
  */
 class ActionManager extends DefaultPluginManager {
 
+  use ContextAwarePluginManagerTrait;
+
   /**
    * Constructs a new class instance.
    *
@@ -38,19 +41,4 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
     $this->setCacheBackend($cache_backend, 'action_info');
   }
 
-  /**
-   * Gets the plugin definitions for this entity type.
-   *
-   * @param string $type
-   *   The entity type name.
-   *
-   * @return array
-   *   An array of plugin definitions for this entity type.
-   */
-  public function getDefinitionsByType($type) {
-    return array_filter($this->getDefinitions(), function ($definition) use ($type) {
-      return $definition['type'] === $type;
-    });
-  }
-
 }
diff --git a/core/lib/Drupal/Core/Action/ConfigurableActionBase.php b/core/lib/Drupal/Core/Action/ConfigurableActionBase.php
index e036880..1bd1e2b 100644
--- a/core/lib/Drupal/Core/Action/ConfigurableActionBase.php
+++ b/core/lib/Drupal/Core/Action/ConfigurableActionBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Action;
 
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
+use Drupal\Component\Plugin\Exception\ContextException;
 use Drupal\Core\Action\ActionBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
@@ -60,4 +61,31 @@ public function calculateDependencies() {
     return array();
   }
 
+  /**
+   * Maps configuration values to the context values if they are not set.
+   *
+   * @todo The configuration options should be removed here and the action
+   * should solely depend on context.
+   */
+  protected function mapConfigurationToContext() {
+    foreach ($this->getContextDefinitions() as $context_name => $definition) {
+      // If there is a value in the configuration we populate the context with
+      // it.
+      if (isset($this->configuration[$context_name])) {
+        $value = NULL;
+        // If a required context is not set we have to catch ContextExceptions.
+        // @todo Use a isSet() method on the context object instead of catching
+        // exceptions. See https://www.drupal.org/node/2367121
+        try {
+          $value = $this->getContextValue($context_name);
+        }
+        catch (ContextException $e) {}
+        // Only populate the context if it has not been set explicitly before.
+        if ($value === NULL) {
+          $this->setContextValue($context_name, $this->configuration[$context_name]);
+        }
+      }
+    }
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Annotation/Action.php b/core/lib/Drupal/Core/Annotation/Action.php
index 5d0937d..986a868 100644
--- a/core/lib/Drupal/Core/Annotation/Action.php
+++ b/core/lib/Drupal/Core/Annotation/Action.php
@@ -51,12 +51,10 @@ class Action extends Plugin {
   public $confirm_form_route_name = '';
 
   /**
-   * The entity type the action can apply to.
+   * An array of context definitions.
    *
-   * @todo Replace with \Drupal\Core\Plugin\Context\Context.
-   *
-   * @var string
+   * @var array
    */
-  public $type = '';
+  public $context = array();
 
 }
diff --git a/core/modules/action/src/ActionAddForm.php b/core/modules/action/src/ActionAddForm.php
index 6d8e4aa..19b9aae 100644
--- a/core/modules/action/src/ActionAddForm.php
+++ b/core/modules/action/src/ActionAddForm.php
@@ -64,7 +64,6 @@ public function buildForm(array $form, FormStateInterface $form_state, $action_i
         $this->entity->setPlugin($id);
         // Derive the label and type from the action definition.
         $this->entity->set('label', $definition['label']);
-        $this->entity->set('type', $definition['type']);
         break;
       }
     }
diff --git a/core/modules/action/src/ActionFormBase.php b/core/modules/action/src/ActionFormBase.php
index e6f0c91..04759dd 100644
--- a/core/modules/action/src/ActionFormBase.php
+++ b/core/modules/action/src/ActionFormBase.php
@@ -85,10 +85,6 @@ public function form(array $form, FormStateInterface $form_state) {
       '#type' => 'value',
       '#value' => $this->entity->get('plugin'),
     );
-    $form['type'] = array(
-      '#type' => 'value',
-      '#value' => $this->entity->getType(),
-    );
 
     if ($this->plugin instanceof PluginFormInterface) {
       $form += $this->plugin->buildConfigurationForm($form, $form_state);
diff --git a/core/modules/action/src/ActionListBuilder.php b/core/modules/action/src/ActionListBuilder.php
index 2d3af86..edb9893 100644
--- a/core/modules/action/src/ActionListBuilder.php
+++ b/core/modules/action/src/ActionListBuilder.php
@@ -79,7 +79,12 @@ public function load() {
    * {@inheritdoc}
    */
   public function buildRow(EntityInterface $entity) {
-    $row['type'] = $entity->getType();
+    // Concatenate all context labels of the action.
+    $contexts = $entity->getPlugin()->getContextDefinitions();
+    array_walk($contexts, function (&$value) {
+      $value = $value->getLabel();
+    });
+    $row['context'] = implode(', ', $contexts);
     $row['label'] = $this->getLabel($entity);
     if ($this->hasConfigurableActions) {
       $row += parent::buildRow($entity);
@@ -92,7 +97,7 @@ public function buildRow(EntityInterface $entity) {
    */
   public function buildHeader() {
     $header = array(
-      'type' => t('Action type'),
+      'context' => t('Action context'),
       'label' => t('Label'),
     ) + parent::buildHeader();
     return $header;
diff --git a/core/modules/action/src/Plugin/Action/EmailAction.php b/core/modules/action/src/Plugin/Action/EmailAction.php
index 2a1e3a9..428de7a 100644
--- a/core/modules/action/src/Plugin/Action/EmailAction.php
+++ b/core/modules/action/src/Plugin/Action/EmailAction.php
@@ -21,7 +21,25 @@
  * @Action(
  *   id = "action_send_email_action",
  *   label = @Translation("Send email"),
- *   type = "system"
+ *   context = {
+ *     "entity" = @ContextDefinition("entity",
+ *       label = @Translation("Entity"),
+ *       description = @Translation("The contextual entity that can be used for token replacements."),
+ *       required = false
+ *     ),
+ *     "recipient" = @ContextDefinition("email",
+ *       label = @Translation("Recipient"),
+ *       description = @Translation("The email address to which the message should be sent.")
+ *     ),
+ *     "subject" = @ContextDefinition("string",
+ *       label = @Translation("Subject"),
+ *       description = @Translation("The subject of the message.")
+ *     ),
+ *     "message" = @ContextDefinition("string",
+ *       label = @Translation("Message"),
+ *       description = @Translation("The message that should be sent.")
+ *     ),
+ *   }
  * )
  */
 class EmailAction extends ConfigurableActionBase implements ContainerFactoryPluginInterface {
@@ -85,12 +103,10 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
-    if (empty($this->configuration['node'])) {
-      $this->configuration['node'] = $entity;
-    }
+  public function execute() {
+    $this->mapConfigurationToContext();
 
-    $recipient = $this->token->replace($this->configuration['recipient'], $this->configuration);
+    $recipient = $this->getContextValue('recipient');
 
     // If the recipient is a registered user with a language preference, use
     // the recipient's preferred language. Otherwise, use the system default
@@ -103,7 +119,11 @@ public function execute($entity = NULL) {
     else {
       $langcode = language_default()->getId();
     }
-    $params = array('context' => $this->configuration);
+
+    $params = array('context' => array(
+      'subject' => $this->getContextValue('subject'),
+      'message' => $this->getContextValue('message'),
+    ));
 
     if (drupal_mail('system', 'action_send_email', $recipient, $langcode, $params)) {
       $this->logger->notice('Sent email to %recipient', array('%recipient' => $recipient));
@@ -114,6 +134,37 @@ public function execute($entity = NULL) {
   }
 
   /**
+   * Maps configuration values to the context values if they are not set.
+   *
+   * @todo The configuration options should be removed here and the action
+   * should solely depend on context.
+   */
+  protected function mapConfigurationToContext() {
+    $entity = $this->getContextValue('entity');
+    if (empty($this->configuration['node']) && $entity) {
+      $this->configuration['node'] = $entity;
+    }
+
+    // First check if a recipient context value is set, otherwise use the value
+    // from the configuration.
+    $recipient = $this->getContextValue('recipient');
+    if (!$recipient) {
+      $recipient = $this->configuration['recipient'];
+      $recipient = $this->token->replace($recipient, $this->configuration);
+      $this->setContextValue('recipient', $recipient);
+    }
+
+    $subject = $this->getContextValue('subject');
+    if (!$subject) {
+      $this->setContextValue('subject', $this->configuration['subject']);
+    }
+    $message = $this->getContextValue('message');
+    if (!$message) {
+      $this->setContextValue('message', $this->configuration['message']);
+    }
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function defaultConfiguration() {
diff --git a/core/modules/action/src/Plugin/Action/GotoAction.php b/core/modules/action/src/Plugin/Action/GotoAction.php
index 833f304..f735594 100644
--- a/core/modules/action/src/Plugin/Action/GotoAction.php
+++ b/core/modules/action/src/Plugin/Action/GotoAction.php
@@ -22,7 +22,12 @@
  * @Action(
  *   id = "action_goto_action",
  *   label = @Translation("Redirect to URL"),
- *   type = "system"
+ *   context = {
+ *     "url" = @ContextDefinition("string",
+ *       label = @Translation("URL"),
+ *       description = @Translation("The URL to which the user should be redirected. This can be an internal URL like node/1234 or an external URL like https://drupal.org.")
+ *     )
+ *   }
  * )
  */
 class GotoAction extends ConfigurableActionBase implements ContainerFactoryPluginInterface {
@@ -72,9 +77,11 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function execute($object = NULL) {
+  public function execute() {
+    $this->mapConfigurationToContext();
+    $path = $this->getContextValue('url');
     $url = $this->urlGenerator
-      ->generateFromPath($this->configuration['url'], array('absolute' => TRUE));
+      ->generateFromPath($path, array('absolute' => TRUE));
     $response = new RedirectResponse($url);
     $listener = function($event) use ($response) {
       $event->setResponse($response);
diff --git a/core/modules/action/src/Plugin/Action/MessageAction.php b/core/modules/action/src/Plugin/Action/MessageAction.php
index 7996514..8d8b2d2 100644
--- a/core/modules/action/src/Plugin/Action/MessageAction.php
+++ b/core/modules/action/src/Plugin/Action/MessageAction.php
@@ -20,7 +20,17 @@
  * @Action(
  *   id = "action_message_action",
  *   label = @Translation("Display a message to the user"),
- *   type = "system"
+ *   context = {
+ *     "node" = @ContextDefinition("entity:node",
+ *       label = @Translation("Node"),
+ *       description = @Translation("The contextual node entity that can be used for token replacements."),
+ *       required = false
+ *     ),
+ *     "message" = @ContextDefinition("string",
+ *       label = @Translation("Message"),
+ *       description = @Translation("The message to be displayed to the current user. You may include placeholders like [node:title], [user:name], and [comment:body] to represent data that will be different each time message is sent. Not all placeholders will be available in all contexts.")
+ *     )
+ *   }
  * )
  */
 class MessageAction extends ConfigurableActionBase implements ContainerFactoryPluginInterface {
@@ -49,12 +59,31 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
-    if (empty($this->configuration['node'])) {
-      $this->configuration['node'] = $entity;
+  public function execute() {
+    $this->mapConfigurationToContext();
+    drupal_set_message($this->getContextValue('message'));
+  }
+
+  /**
+   * Maps configuration values to the context values if they are not set.
+   *
+   * @todo The configuration options should be removed here and the action
+   * should solely depend on context.
+   */
+  protected function mapConfigurationToContext() {
+    $node = $this->getContextValue('node');
+    if (empty($this->configuration['node']) && $node) {
+      $this->configuration['node'] = $node;
+    }
+
+    // First check if a message context value is set, otherwise use the value
+    // from the configuration.
+    $message = $this->getContextValue('message');
+    if (!$message) {
+      $message = $this->configuration['message'];
+      $message = $this->token->replace(Xss::filterAdmin($message), $this->configuration);
+      $this->setContextValue('message', $message);
     }
-    $message = $this->token->replace(Xss::filterAdmin($this->configuration['message']), $this->configuration);
-    drupal_set_message($message);
   }
 
   /**
diff --git a/core/modules/action/src/Tests/ConfigurationTest.php b/core/modules/action/src/Tests/ConfigurationTest.php
index 7f226dd..23864be 100644
--- a/core/modules/action/src/Tests/ConfigurationTest.php
+++ b/core/modules/action/src/Tests/ConfigurationTest.php
@@ -43,7 +43,8 @@ function testActionConfiguration() {
     $edit = array();
     $action_label = $this->randomMachineName();
     $edit['label'] = $action_label;
-    $edit['id'] = strtolower($action_label);
+    $aid = strtolower($action_label);
+    $edit['id'] = $aid;
     $edit['url'] = 'admin';
     $this->drupalPostForm('admin/config/system/actions/add/' . Crypt::hashBase64('action_goto_action'), $edit, t('Save'));
     $this->assertResponse(200);
@@ -53,9 +54,7 @@ function testActionConfiguration() {
     $this->assertText($action_label, "Make sure the action label appears on the configuration page after we've saved the complex action.");
 
     // Make another POST request to the action edit page.
-    $this->clickLink(t('Configure'));
-    preg_match('|admin/config/system/actions/configure/(.+)|', $this->getUrl(), $matches);
-    $aid = $matches[1];
+    $this->drupalGet('admin/config/system/actions/configure/' . $aid);
     $edit = array();
     $new_action_label = $this->randomMachineName();
     $edit['label'] = $new_action_label;
@@ -68,7 +67,7 @@ function testActionConfiguration() {
     $this->assertNoText($action_label, "Make sure the old action label does NOT appear on the configuration page after we've updated the complex action.");
     $this->assertText($new_action_label, "Make sure the action label appears on the configuration page after we've updated the complex action.");
 
-    $this->clickLink(t('Configure'));
+    $this->drupalGet('admin/config/system/actions/configure/' . $aid);
     $element = $this->xpath('//input[@type="text" and @value="admin"]');
     $this->assertTrue(!empty($element), 'Make sure the URL appears when re-editing the action.');
 
diff --git a/core/modules/comment/src/Plugin/Action/PublishComment.php b/core/modules/comment/src/Plugin/Action/PublishComment.php
index 41ed873..7b26bb7 100644
--- a/core/modules/comment/src/Plugin/Action/PublishComment.php
+++ b/core/modules/comment/src/Plugin/Action/PublishComment.php
@@ -16,7 +16,11 @@
  * @Action(
  *   id = "comment_publish_action",
  *   label = @Translation("Publish comment"),
- *   type = "comment"
+ *   context = {
+ *     "comment" = @ContextDefinition("entity:comment",
+ *       label = @Translation("Comment")
+ *     )
+ *   }
  * )
  */
 class PublishComment extends ActionBase {
@@ -24,7 +28,8 @@ class PublishComment extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($comment = NULL) {
+  public function execute() {
+    $comment = $this->getContextValue('comment');
     $comment->setPublished(TRUE);
     $comment->save();
   }
diff --git a/core/modules/comment/src/Plugin/Action/SaveComment.php b/core/modules/comment/src/Plugin/Action/SaveComment.php
index 5ce763e..77c184e 100644
--- a/core/modules/comment/src/Plugin/Action/SaveComment.php
+++ b/core/modules/comment/src/Plugin/Action/SaveComment.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "comment_save_action",
  *   label = @Translation("Save comment"),
- *   type = "comment"
+ *   context = {
+ *     "comment" = @ContextDefinition("entity:comment",
+ *       label = @Translation("Comment")
+ *     )
+ *   }
  * )
  */
 class SaveComment extends ActionBase {
@@ -23,7 +27,8 @@ class SaveComment extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($comment = NULL) {
+  public function execute() {
+    $comment = $this->getContextValue('comment');
     $comment->save();
   }
 
diff --git a/core/modules/comment/src/Plugin/Action/UnpublishByKeywordComment.php b/core/modules/comment/src/Plugin/Action/UnpublishByKeywordComment.php
index 3d10bcb..8441250 100644
--- a/core/modules/comment/src/Plugin/Action/UnpublishByKeywordComment.php
+++ b/core/modules/comment/src/Plugin/Action/UnpublishByKeywordComment.php
@@ -9,7 +9,6 @@
 
 use Drupal\Component\Utility\Tags;
 use Drupal\Core\Action\ConfigurableActionBase;
-use Drupal\comment\CommentInterface;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
@@ -18,18 +17,32 @@
  * @Action(
  *   id = "comment_unpublish_by_keyword_action",
  *   label = @Translation("Unpublish comment containing keyword(s)"),
- *   type = "comment"
+ *   context = {
+ *     "comment" = @ContextDefinition("entity:comment",
+ *       label = @Translation("Comment")
+ *     ),
+ *     "keywords" = @ContextDefinition("string",
+ *       label = @Translation("Keywords"),
+ *       description = @Translation("The comment will be unpublished if it contains any of the phrases. Use a case-sensitive, comma-separated list of phrases. Example: funny, bungee jumping, ""Company, Inc."""),
+ *       multiple = true
+ *     )
+ *   }
  * )
  */
 class UnpublishByKeywordComment extends ConfigurableActionBase {
 
   /**
    * {@inheritdoc}
+   *
+   * @todo The configuration options should be removed here and the action
+   * should solely depend on context.
    */
-  public function execute($comment = NULL) {
+  public function execute() {
+    $this->mapConfigurationToContext();
+    $comment = $this->getContextValue('comment');
     $build = comment_view($comment);
     $text = drupal_render($build);
-    foreach ($this->configuration['keywords'] as $keyword) {
+    foreach ($this->getContextValue('keywords') as $keyword) {
       if (strpos($text, $keyword) !== FALSE) {
         $comment->setPublished(FALSE);
         $comment->save();
diff --git a/core/modules/comment/src/Plugin/Action/UnpublishComment.php b/core/modules/comment/src/Plugin/Action/UnpublishComment.php
index 74d565a..a4dd66e 100644
--- a/core/modules/comment/src/Plugin/Action/UnpublishComment.php
+++ b/core/modules/comment/src/Plugin/Action/UnpublishComment.php
@@ -16,7 +16,11 @@
  * @Action(
  *   id = "comment_unpublish_action",
  *   label = @Translation("Unpublish comment"),
- *   type = "comment"
+ *   context = {
+ *     "comment" = @ContextDefinition("entity:comment",
+ *       label = @Translation("Comment")
+ *     )
+ *   }
  * )
  */
 class UnpublishComment extends ActionBase {
@@ -24,7 +28,8 @@ class UnpublishComment extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($comment = NULL) {
+  public function execute() {
+    $comment = $this->getContextValue('comment');
     $comment->setPublished(FALSE);
     $comment->save();
   }
diff --git a/core/modules/comment/src/Tests/CommentActionsTest.php b/core/modules/comment/src/Tests/CommentActionsTest.php
index 67618da..3256d6c 100644
--- a/core/modules/comment/src/Tests/CommentActionsTest.php
+++ b/core/modules/comment/src/Tests/CommentActionsTest.php
@@ -34,12 +34,16 @@ function testCommentPublishUnpublishActions() {
 
     // Unpublish a comment.
     $action = entity_load('action', 'comment_unpublish_action');
-    $action->execute(array($comment));
+    $action_plugin = $action->getPlugin();
+    $action_plugin->setContextValue('comment', $comment);
+    $action_plugin->execute();
     $this->assertTrue($comment->isPublished() === FALSE, 'Comment was unpublished');
 
     // Publish a comment.
     $action = entity_load('action', 'comment_publish_action');
-    $action->execute(array($comment));
+    $action_plugin = $action->getPlugin();
+    $action_plugin->setContextValue('comment', $comment);
+    $action_plugin->execute();
     $this->assertTrue($comment->isPublished() === TRUE, 'Comment was published');
   }
 
@@ -68,7 +72,9 @@ function testCommentUnpublishByKeyword() {
 
     $this->assertTrue($comment->isPublished() === TRUE, 'The comment status was set to published.');
 
-    $action->execute(array($comment));
+    $action_plugin = $action->getPlugin();
+    $action_plugin->setContextValue('comment', $comment);
+    $action_plugin->execute();
     $this->assertTrue($comment->isPublished() === FALSE, 'The comment status was set to not published.');
   }
 
diff --git a/core/modules/node/src/Plugin/Action/AssignOwnerNode.php b/core/modules/node/src/Plugin/Action/AssignOwnerNode.php
index 17e62d1..ce2776a 100644
--- a/core/modules/node/src/Plugin/Action/AssignOwnerNode.php
+++ b/core/modules/node/src/Plugin/Action/AssignOwnerNode.php
@@ -19,7 +19,15 @@
  * @Action(
  *   id = "node_assign_owner_action",
  *   label = @Translation("Change the author of content"),
- *   type = "node"
+ *   context = {
+ *     "node" = @ContextDefinition("entity:node",
+ *       label = @Translation("Node")
+ *     ),
+ *     "user" = @ContextDefinition("entity:user",
+ *       label = @Translation("User"),
+ *       description = @Translation("The user to which you would like to assign ownership.")
+ *     )
+ *   }
  * )
  */
 class AssignOwnerNode extends ConfigurableActionBase implements ContainerFactoryPluginInterface {
@@ -60,10 +68,20 @@ public static function create(ContainerInterface $container, array $configuratio
 
   /**
    * {@inheritdoc}
+   *
+   * @todo The configuration options should be removed here and the action
+   * should solely depend on context.
    */
-  public function execute($entity = NULL) {
-    $entity->uid = $this->configuration['owner_uid'];
-    $entity->save();
+  public function execute() {
+    $node = $this->getContextValue('node');
+    $user = $this->getContextValue('user');
+    if ($user) {
+      $node->setOwner($user);
+    }
+    else {
+      $node->setOwnerId($this->configuration['owner_uid']);
+    }
+    $node->save();
   }
 
   /**
diff --git a/core/modules/node/src/Plugin/Action/DeleteNode.php b/core/modules/node/src/Plugin/Action/DeleteNode.php
index e71b581..59c57a8 100644
--- a/core/modules/node/src/Plugin/Action/DeleteNode.php
+++ b/core/modules/node/src/Plugin/Action/DeleteNode.php
@@ -18,7 +18,11 @@
  * @Action(
  *   id = "node_delete_action",
  *   label = @Translation("Delete selected content"),
- *   type = "node",
+ *   context = {
+ *     "node" = @ContextDefinition("entity:node",
+ *       label = @Translation("Node")
+ *     )
+ *   },
  *   confirm_form_route_name = "node.multiple_delete_confirm"
  * )
  */
@@ -59,15 +63,16 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function executeMultiple(array $entities) {
-    $this->tempStore->set(\Drupal::currentUser()->id(), $entities);
+  public function executeMultiple($context_name, array $context_values) {
+    $this->tempStore->set(\Drupal::currentUser()->id(), $context_values);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function execute($object = NULL) {
-    $this->executeMultiple(array($object));
+  public function execute() {
+    $node = $this->getContextValue('node');
+    $this->executeMultiple(array($node), 'node');
   }
 
 }
diff --git a/core/modules/node/src/Plugin/Action/DemoteNode.php b/core/modules/node/src/Plugin/Action/DemoteNode.php
index e490ecb..065a952 100644
--- a/core/modules/node/src/Plugin/Action/DemoteNode.php
+++ b/core/modules/node/src/Plugin/Action/DemoteNode.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "node_unpromote_action",
  *   label = @Translation("Demote selected content from front page"),
- *   type = "node"
+ *   context = {
+ *     "node" = @ContextDefinition("entity:node",
+ *       label = @Translation("Node")
+ *     )
+ *   }
  * )
  */
 class DemoteNode extends ActionBase {
@@ -23,7 +27,8 @@ class DemoteNode extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
+  public function execute() {
+    $entity = $this->getContextValue('node');
     $entity->setPromoted(FALSE);
     $entity->save();
   }
diff --git a/core/modules/node/src/Plugin/Action/PromoteNode.php b/core/modules/node/src/Plugin/Action/PromoteNode.php
index 0cfc316..6563392 100644
--- a/core/modules/node/src/Plugin/Action/PromoteNode.php
+++ b/core/modules/node/src/Plugin/Action/PromoteNode.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "node_promote_action",
  *   label = @Translation("Promote selected content to front page"),
- *   type = "node"
+ *   context = {
+ *     "node" = @ContextDefinition("entity:node",
+ *       label = @Translation("Node")
+ *     )
+ *   }
  * )
  */
 class PromoteNode extends ActionBase {
@@ -23,7 +27,8 @@ class PromoteNode extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
+  public function execute() {
+    $entity = $this->getContextValue('node');
     $entity->setPublished(TRUE);
     $entity->setPromoted(TRUE);
     $entity->save();
diff --git a/core/modules/node/src/Plugin/Action/PublishNode.php b/core/modules/node/src/Plugin/Action/PublishNode.php
index 20da55e..a0c11f0 100644
--- a/core/modules/node/src/Plugin/Action/PublishNode.php
+++ b/core/modules/node/src/Plugin/Action/PublishNode.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "node_publish_action",
  *   label = @Translation("Publish selected content"),
- *   type = "node"
+ *   context = {
+ *     "node" = @ContextDefinition("entity:node",
+ *       label = @Translation("Node")
+ *     )
+ *   }
  * )
  */
 class PublishNode extends ActionBase {
@@ -23,7 +27,8 @@ class PublishNode extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
+  public function execute() {
+    $entity = $this->getContextValue('node');
     $entity->status = NODE_PUBLISHED;
     $entity->save();
   }
diff --git a/core/modules/node/src/Plugin/Action/SaveNode.php b/core/modules/node/src/Plugin/Action/SaveNode.php
index b758b72..8c69493 100644
--- a/core/modules/node/src/Plugin/Action/SaveNode.php
+++ b/core/modules/node/src/Plugin/Action/SaveNode.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "node_save_action",
  *   label = @Translation("Save content"),
- *   type = "node"
+ *   context = {
+ *     "node" = @ContextDefinition("entity:node",
+ *       label = @Translation("Node")
+ *     )
+ *   }
  * )
  */
 class SaveNode extends ActionBase {
@@ -23,7 +27,8 @@ class SaveNode extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
+  public function execute() {
+    $entity = $this->getContextValue('node');
     $entity->save();
   }
 
diff --git a/core/modules/node/src/Plugin/Action/StickyNode.php b/core/modules/node/src/Plugin/Action/StickyNode.php
index c4613ce..1241e02 100644
--- a/core/modules/node/src/Plugin/Action/StickyNode.php
+++ b/core/modules/node/src/Plugin/Action/StickyNode.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "node_make_sticky_action",
  *   label = @Translation("Make selected content sticky"),
- *   type = "node"
+ *   context = {
+ *     "node" = @ContextDefinition("entity:node",
+ *       label = @Translation("Node")
+ *     )
+ *   }
  * )
  */
 class StickyNode extends ActionBase {
@@ -23,7 +27,8 @@ class StickyNode extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
+  public function execute() {
+    $entity = $this->getContextValue('node');
     $entity->status = NODE_PUBLISHED;
     $entity->sticky = NODE_STICKY;
     $entity->save();
diff --git a/core/modules/node/src/Plugin/Action/UnpublishByKeywordNode.php b/core/modules/node/src/Plugin/Action/UnpublishByKeywordNode.php
index 60bd836..c0f1f6e 100644
--- a/core/modules/node/src/Plugin/Action/UnpublishByKeywordNode.php
+++ b/core/modules/node/src/Plugin/Action/UnpublishByKeywordNode.php
@@ -17,16 +17,31 @@
  * @Action(
  *   id = "node_unpublish_by_keyword_action",
  *   label = @Translation("Unpublish content containing keyword(s)"),
- *   type = "node"
+ *   context = {
+ *     "node" = @ContextDefinition("entity:node",
+ *       label = @Translation("Node")
+ *     ),
+ *     "keywords" = @ContextDefinition("string",
+ *       label = @Translation("Keywords"),
+ *       description = @Translation("The content will be unpublished if it contains any of the phrases. Use a case-sensitive, comma-separated list of phrases. Example: funny, bungee jumping, ""Company, Inc."""),
+ *       multiple = true
+ *     )
+ *   }
  * )
  */
 class UnpublishByKeywordNode extends ConfigurableActionBase {
 
   /**
    * {@inheritdoc}
+   *
+   * @todo The configuration options should be removed here and the action
+   * should solely depend on context.
    */
-  public function execute($node = NULL) {
-    foreach ($this->configuration['keywords'] as $keyword) {
+  public function execute() {
+    $node = $this->getContextValue('node');
+    $keywords = $this->getContextValue('keywords');
+
+    foreach ($keywords as $keyword) {
       $elements = node_view(clone $node);
       if (strpos(drupal_render($elements), $keyword) !== FALSE || strpos($node->label(), $keyword) !== FALSE) {
         $node->setPublished(FALSE);
diff --git a/core/modules/node/src/Plugin/Action/UnpublishNode.php b/core/modules/node/src/Plugin/Action/UnpublishNode.php
index d462d6d..7f6098a 100644
--- a/core/modules/node/src/Plugin/Action/UnpublishNode.php
+++ b/core/modules/node/src/Plugin/Action/UnpublishNode.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "node_unpublish_action",
  *   label = @Translation("Unpublish selected content"),
- *   type = "node"
+ *   context = {
+ *     "node" = @ContextDefinition("entity:node",
+ *       label = @Translation("Node")
+ *     )
+ *   }
  * )
  */
 class UnpublishNode extends ActionBase {
@@ -23,7 +27,8 @@ class UnpublishNode extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
+  public function execute() {
+    $entity = $this->getContextValue('node');
     $entity->status = NODE_NOT_PUBLISHED;
     $entity->save();
   }
diff --git a/core/modules/node/src/Plugin/Action/UnstickyNode.php b/core/modules/node/src/Plugin/Action/UnstickyNode.php
index 204b9d5..8010953 100644
--- a/core/modules/node/src/Plugin/Action/UnstickyNode.php
+++ b/core/modules/node/src/Plugin/Action/UnstickyNode.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "node_make_unsticky_action",
  *   label = @Translation("Make selected content not sticky"),
- *   type = "node"
+ *   context = {
+ *     "node" = @ContextDefinition("entity:node",
+ *       label = @Translation("Node")
+ *     )
+ *   }
  * )
  */
 class UnstickyNode extends ActionBase {
@@ -23,7 +27,8 @@ class UnstickyNode extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
+  public function execute() {
+    $entity = $this->getContextValue('node');
     $entity->sticky = NODE_NOT_STICKY;
     $entity->save();
   }
diff --git a/core/modules/node/tests/src/Unit/Plugin/views/field/NodeBulkFormTest.php b/core/modules/node/tests/src/Unit/Plugin/views/field/NodeBulkFormTest.php
index 82836e0..4bad71b 100644
--- a/core/modules/node/tests/src/Unit/Plugin/views/field/NodeBulkFormTest.php
+++ b/core/modules/node/tests/src/Unit/Plugin/views/field/NodeBulkFormTest.php
@@ -8,6 +8,8 @@
 namespace Drupal\Tests\node\Unit\Plugin\views\field;
 
 use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\Plugin\Context\ContextHandler;
 use Drupal\node\Plugin\views\field\NodeBulkForm;
 use Drupal\Tests\UnitTestCase;
 
@@ -30,26 +32,44 @@ protected function tearDown() {
    * Tests the constructor assignment of actions.
    */
   public function testConstructor() {
-    $actions = array();
+    $action_configs = array();
 
     for ($i = 1; $i <= 2; $i++) {
-      $action = $this->getMock('\Drupal\system\ActionConfigEntityInterface');
+      $action = $this->getMock('\Drupal\Core\Action\ActionInterface');
       $action->expects($this->any())
-        ->method('getType')
-        ->will($this->returnValue('node'));
-      $actions[$i] = $action;
+        ->method('getPluginDefinition')
+        ->will($this->returnValue(array(
+          'context' => array(
+            'node' => new ContextDefinition('entity:node')
+          )
+        )));
+
+      $action_config = $this->getMock('\Drupal\system\ActionConfigEntityInterface');
+      $action_config->expects($this->any())
+        ->method('getPlugin')
+        ->will($this->returnValue($action));
+      $action_configs[$i] = $action_config;
     }
 
-    $action = $this->getMock('\Drupal\system\ActionConfigEntityInterface');
+    $action = $this->getMock('\Drupal\Core\Action\ActionInterface');
     $action->expects($this->any())
-      ->method('getType')
-      ->will($this->returnValue('user'));
-    $actions[] = $action;
+      ->method('getPluginDefinition')
+      ->will($this->returnValue(array(
+        'context' => array(
+          'user' => new ContextDefinition('entity:user')
+        )
+      )));
+
+    $action_config = $this->getMock('\Drupal\system\ActionConfigEntityInterface');
+    $action_config->expects($this->any())
+      ->method('getPlugin')
+      ->will($this->returnValue($action));
+    $action_configs[] = $action_config;
 
     $entity_storage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
     $entity_storage->expects($this->any())
       ->method('loadMultiple')
-      ->will($this->returnValue($actions));
+      ->will($this->returnValue($action_configs));
 
     $views_data = $this->getMockBuilder('Drupal\views\ViewsData')
       ->disableOriginalConstructor()
@@ -80,10 +100,10 @@ public function testConstructor() {
     $definition['title'] = '';
     $options = array();
 
-    $node_bulk_form = new NodeBulkForm(array(), 'node_bulk_form', $definition, $entity_storage);
+    $node_bulk_form = new NodeBulkForm(array(), 'node_bulk_form', $definition, $entity_storage, new ContextHandler());
     $node_bulk_form->init($executable, $display, $options);
 
-    $this->assertAttributeEquals(array_slice($actions, 0, -1, TRUE), 'actions', $node_bulk_form);
+    $this->assertAttributeEquals(array_slice($action_configs, 0, -1, TRUE), 'actions', $node_bulk_form);
   }
 
 }
diff --git a/core/modules/system/src/ActionConfigEntityInterface.php b/core/modules/system/src/ActionConfigEntityInterface.php
index 32b41b0..3343600 100644
--- a/core/modules/system/src/ActionConfigEntityInterface.php
+++ b/core/modules/system/src/ActionConfigEntityInterface.php
@@ -22,13 +22,6 @@
   public function isConfigurable();
 
   /**
-   * Returns the operation type.
-   *
-   * @return string
-   */
-  public function getType();
-
-  /**
    * Returns the operation plugin.
    *
    * @return \Drupal\Core\Action\ActionInterface
diff --git a/core/modules/system/src/Entity/Action.php b/core/modules/system/src/Entity/Action.php
index a7176db..8b6b173 100644
--- a/core/modules/system/src/Entity/Action.php
+++ b/core/modules/system/src/Entity/Action.php
@@ -44,13 +44,6 @@ class Action extends ConfigEntityBase implements ActionConfigEntityInterface, En
   public $label;
 
   /**
-   * The action type.
-   *
-   * @var string
-   */
-  protected $type;
-
-  /**
    * The configuration of the action.
    *
    * @var array
@@ -116,36 +109,8 @@ public function getPluginDefinition() {
   /**
    * {@inheritdoc}
    */
-  public function execute(array $entities) {
-    return $this->getPlugin()->executeMultiple($entities);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function isConfigurable() {
     return $this->getPlugin() instanceof ConfigurablePluginInterface;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getType() {
-    return $this->type;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function sort(ConfigEntityInterface $a, ConfigEntityInterface $b) {
-    /** @var \Drupal\system\ActionConfigEntityInterface $a */
-    /** @var \Drupal\system\ActionConfigEntityInterface $b */
-    $a_type = $a->getType();
-    $b_type = $b->getType();
-    if ($a_type != $b_type) {
-      return strnatcasecmp($a_type, $b_type);
-    }
-    return parent::sort($a, $b);
-  }
-
 }
diff --git a/core/modules/system/src/Plugin/views/field/BulkForm.php b/core/modules/system/src/Plugin/views/field/BulkForm.php
index 06a7d3a..15aa357 100644
--- a/core/modules/system/src/Plugin/views/field/BulkForm.php
+++ b/core/modules/system/src/Plugin/views/field/BulkForm.php
@@ -9,6 +9,9 @@
 
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\Plugin\Context\ContextHandlerInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\Plugin\views\style\Table;
@@ -38,6 +41,13 @@ class BulkForm extends FieldPluginBase {
   protected $actions = array();
 
   /**
+   * The context handler.
+   *
+   * @var \Drupal\Core\Plugin\Context\ContextHandlerInterface
+   */
+  protected $contextHandler;
+
+  /**
    * Constructs a new BulkForm object.
    *
    * @param array $configuration
@@ -48,18 +58,24 @@ class BulkForm extends FieldPluginBase {
    *   The plugin implementation definition.
    * @param \Drupal\Core\Entity\EntityStorageInterface $storage
    *   The action storage.
+   * @param \Drupal\Core\Plugin\Context\ContextHandlerInterface $context_handler
+   *   The context handler.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $storage) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $storage, ContextHandlerInterface $context_handler) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
 
     $this->actionStorage = $storage;
+    $this->contextHandler = $context_handler;
   }
 
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
-    return new static($configuration, $plugin_id, $plugin_definition, $container->get('entity.manager')->getStorage('action'));
+    return new static($configuration, $plugin_id, $plugin_definition,
+      $container->get('entity.manager')->getStorage('action'),
+      $container->get('context.handler')
+    );
   }
 
   /**
@@ -69,9 +85,12 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
     parent::init($view, $display, $options);
 
     $entity_type = $this->getEntityType();
-    // Filter the actions to only include those for this entity type.
-    $this->actions = array_filter($this->actionStorage->loadMultiple(), function ($action) use ($entity_type) {
-      return $action->getType() == $entity_type;
+    $context_handler = $this->contextHandler;
+    $match_context = array('context' => new Context(new ContextDefinition("entity:$entity_type")));
+    // Filter the actions to only include those that match for this entity type.
+    $this->actions = array_filter($this->actionStorage->loadMultiple(), function ($action) use ($context_handler, $match_context) {
+      $filtered = $context_handler->filterPluginDefinitionsByContexts($match_context, array($action->getPlugin()->getPluginDefinition()));
+      return !empty($filtered);
     });
   }
 
@@ -261,7 +280,20 @@ public function viewsFormSubmit(&$form, FormStateInterface $form_state) {
       }
 
       $action = $this->actions[$form_state->getValue('action')];
-      $action->execute($entities);
+      // We need to find out on what context on the action plugin we will set
+      // the entities.
+      $action_plugin = $action->getPlugin();
+      $entity_type = $this->getEntityType();
+      $contexts = $action_plugin->getContextDefinitions();
+
+      // Pick the first context that matches the data type.
+      foreach ($contexts as $context_name => $context_definition) {
+        $type = $context_definition->getDataType();
+        if ($type == "entity:$entity_type") {
+          break;
+        }
+      }
+      $action_plugin->executeMultiple($context_name, $entities);
 
       $operation_definition = $action->getPluginDefinition();
       if (!empty($operation_definition['confirm_form_route_name'])) {
diff --git a/core/modules/system/src/Tests/Action/ActionUnitTest.php b/core/modules/system/src/Tests/Action/ActionUnitTest.php
index d442399..c0a7cac 100644
--- a/core/modules/system/src/Tests/Action/ActionUnitTest.php
+++ b/core/modules/system/src/Tests/Action/ActionUnitTest.php
@@ -7,8 +7,10 @@
 
 namespace Drupal\system\Tests\Action;
 
-use Drupal\simpletest\DrupalUnitTestBase;
 use Drupal\Core\Action\ActionInterface;
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\simpletest\DrupalUnitTestBase;
 
 /**
  * Tests action plugins.
@@ -52,8 +54,10 @@ public function testOperations() {
     $definition = $this->actionManager->getDefinition('action_test_no_type');
     $this->assertTrue(!empty($definition), 'The test action definition is found.');
 
-    $definitions = $this->actionManager->getDefinitionsByType('user');
-    $this->assertTrue(empty($definitions['action_test_no_type']), 'An action with no type is not found.');
+    $definitions = $this->actionManager->getDefinitionsForContexts(array(
+      new Context(new ContextDefinition('entity:user'))
+    ));
+    $this->assertFalse(empty($definitions['action_test_no_type']), 'An action with no user type is found.');
 
     // Create an instance of the 'save entity' action.
     $action = $this->actionManager->createInstance('action_test_save_entity');
@@ -67,7 +71,8 @@ public function testOperations() {
     $this->assertEqual(count($loaded_accounts), 0);
 
     // Execute the 'save entity' action.
-    $action->execute($account);
+    $action->setContextValue('user', $account);
+    $action->execute();
     $loaded_accounts = $user_storage->loadMultiple();
     $this->assertEqual(count($loaded_accounts), 1);
     $account = reset($loaded_accounts);
diff --git a/core/modules/system/tests/modules/action_test/src/Plugin/Action/NoType.php b/core/modules/system/tests/modules/action_test/src/Plugin/Action/NoType.php
index 7f18b57..048da67 100644
--- a/core/modules/system/tests/modules/action_test/src/Plugin/Action/NoType.php
+++ b/core/modules/system/tests/modules/action_test/src/Plugin/Action/NoType.php
@@ -10,11 +10,11 @@
 use Drupal\Core\Action\ActionBase;
 
 /**
- * Provides an operation with no type specified.
+ * Provides an operation with no context specified.
  *
  * @Action(
  *   id = "action_test_no_type",
- *   label = @Translation("An operation with no type specified")
+ *   label = @Translation("An operation with no context specified")
  * )
  */
 class NoType extends ActionBase {
@@ -22,7 +22,7 @@ class NoType extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
+  public function execute() {
   }
 
 }
diff --git a/core/modules/system/tests/modules/action_test/src/Plugin/Action/SaveEntity.php b/core/modules/system/tests/modules/action_test/src/Plugin/Action/SaveEntity.php
index e3d296f..5ffa289 100644
--- a/core/modules/system/tests/modules/action_test/src/Plugin/Action/SaveEntity.php
+++ b/core/modules/system/tests/modules/action_test/src/Plugin/Action/SaveEntity.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "action_test_save_entity",
  *   label = @Translation("Saves entities"),
- *   type = "user"
+ *   context = {
+ *     "user" = @ContextDefinition("entity:user",
+ *       label = @Translation("User")
+ *     )
+ *   }
  * )
  */
 class SaveEntity extends ActionBase {
@@ -23,7 +27,8 @@ class SaveEntity extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($entity = NULL) {
+  public function execute() {
+    $entity = $this->getContextValue('user');
     $entity->save();
   }
 
diff --git a/core/modules/user/src/Plugin/Action/AddRoleUser.php b/core/modules/user/src/Plugin/Action/AddRoleUser.php
index acf4dd9..a2f09da 100644
--- a/core/modules/user/src/Plugin/Action/AddRoleUser.php
+++ b/core/modules/user/src/Plugin/Action/AddRoleUser.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "user_add_role_action",
  *   label = @Translation("Add a role to the selected users"),
- *   type = "user"
+ *   context = {
+ *     "user" = @ContextDefinition("entity:user",
+ *       label = @Translation("User")
+ *     )
+ *   }
  * )
  */
 class AddRoleUser extends ChangeUserRoleBase {
@@ -23,10 +27,11 @@ class AddRoleUser extends ChangeUserRoleBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($account = NULL) {
+  public function execute() {
+    $account = $this->getContextValue('user');
     $rid = $this->configuration['rid'];
     // Skip adding the role to the user if they already have it.
-    if ($account !== FALSE && !$account->hasRole($rid)) {
+    if (!$account->hasRole($rid)) {
       // For efficiency manually save the original account before applying
       // any changes.
       $account->original = clone $account;
diff --git a/core/modules/user/src/Plugin/Action/BlockUser.php b/core/modules/user/src/Plugin/Action/BlockUser.php
index a488f31..2a22dcc 100644
--- a/core/modules/user/src/Plugin/Action/BlockUser.php
+++ b/core/modules/user/src/Plugin/Action/BlockUser.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "user_block_user_action",
  *   label = @Translation("Block the selected users"),
- *   type = "user"
+ *   context = {
+ *     "user" = @ContextDefinition("entity:user",
+ *       label = @Translation("User")
+ *     )
+ *   }
  * )
  */
 class BlockUser extends ActionBase {
@@ -23,9 +27,10 @@ class BlockUser extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($account = NULL) {
+  public function execute() {
+    $account = $this->getContextValue('user');
     // Skip blocking user if they are already blocked.
-    if ($account !== FALSE && $account->isActive()) {
+    if ($account->isActive()) {
       // For efficiency manually save the original account before applying any
       // changes.
       $account->original = clone $account;
diff --git a/core/modules/user/src/Plugin/Action/CancelUser.php b/core/modules/user/src/Plugin/Action/CancelUser.php
index 6c0e392..c0e1443 100644
--- a/core/modules/user/src/Plugin/Action/CancelUser.php
+++ b/core/modules/user/src/Plugin/Action/CancelUser.php
@@ -18,7 +18,11 @@
  * @Action(
  *   id = "user_cancel_user_action",
  *   label = @Translation("Cancel the selected user accounts"),
- *   type = "user",
+ *   context = {
+ *     "user" = @ContextDefinition("entity:user",
+ *       label = @Translation("User")
+ *     )
+ *   },
  *   confirm_form_route_name = "user.multiple_cancel_confirm"
  * )
  */
@@ -59,15 +63,16 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function executeMultiple(array $entities) {
-    $this->tempStoreFactory->get('user_user_operations_cancel')->set(\Drupal::currentUser()->id(), $entities);
+  public function executeMultiple($context_name, array $context_values) {
+    $this->tempStoreFactory->get('user_user_operations_cancel')->set(\Drupal::currentUser()->id(), $context_values);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function execute($object = NULL) {
-    $this->executeMultiple(array($object));
+  public function execute() {
+    $user = $this->getContextValue('user');
+    $this->executeMultiple(array($user), 'user');
   }
 
 }
diff --git a/core/modules/user/src/Plugin/Action/RemoveRoleUser.php b/core/modules/user/src/Plugin/Action/RemoveRoleUser.php
index e63a70a..54df305 100644
--- a/core/modules/user/src/Plugin/Action/RemoveRoleUser.php
+++ b/core/modules/user/src/Plugin/Action/RemoveRoleUser.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "user_remove_role_action",
  *   label = @Translation("Remove a role from the selected users"),
- *   type = "user"
+ *   context = {
+ *     "user" = @ContextDefinition("entity:user",
+ *       label = @Translation("User")
+ *     )
+ *   }
  * )
  */
 class RemoveRoleUser extends ChangeUserRoleBase {
@@ -23,10 +27,11 @@ class RemoveRoleUser extends ChangeUserRoleBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($account = NULL) {
+  public function execute() {
+    $account = $this->getContextValue('user');
     $rid = $this->configuration['rid'];
     // Skip removing the role from the user if they already don't have it.
-    if ($account !== FALSE && $account->hasRole($rid)) {
+    if ($account->hasRole($rid)) {
       // For efficiency manually save the original account before applying
       // any changes.
       $account->original = clone $account;
diff --git a/core/modules/user/src/Plugin/Action/UnblockUser.php b/core/modules/user/src/Plugin/Action/UnblockUser.php
index 9c30ebc..9470f04 100644
--- a/core/modules/user/src/Plugin/Action/UnblockUser.php
+++ b/core/modules/user/src/Plugin/Action/UnblockUser.php
@@ -15,7 +15,11 @@
  * @Action(
  *   id = "user_unblock_user_action",
  *   label = @Translation("Unblock the selected users"),
- *   type = "user"
+ *   context = {
+ *     "user" = @ContextDefinition("entity:user",
+ *       label = @Translation("User")
+ *     )
+ *   }
  * )
  */
 class UnblockUser extends ActionBase {
@@ -23,9 +27,10 @@ class UnblockUser extends ActionBase {
   /**
    * {@inheritdoc}
    */
-  public function execute($account = NULL) {
+  public function execute() {
+    $account = $this->getContextValue('user');
     // Skip unblocking user if they are already unblocked.
-    if ($account !== FALSE && $account->isBlocked()) {
+    if ($account->isBlocked()) {
       $account->activate();
       $account->save();
     }
diff --git a/core/modules/user/tests/src/Unit/Plugin/Action/AddRoleUserTest.php b/core/modules/user/tests/src/Unit/Plugin/Action/AddRoleUserTest.php
index a2f9e9c..cc0fa24 100644
--- a/core/modules/user/tests/src/Unit/Plugin/Action/AddRoleUserTest.php
+++ b/core/modules/user/tests/src/Unit/Plugin/Action/AddRoleUserTest.php
@@ -7,8 +7,6 @@
 
 namespace Drupal\Tests\user\Unit\Plugin\Action;
 
-use Drupal\user\Plugin\Action\AddRoleUser;
-
 /**
  * @coversDefaultClass \Drupal\user\Plugin\Action\AddRoleUser
  * @group user
@@ -28,9 +26,10 @@ public function testExecuteAddExistingRole() {
       ->will($this->returnValue(TRUE));
 
     $config = array('rid' => 'test_role_1');
-    $remove_role_plugin = new AddRoleUser($config, 'user_add_role_action', array('type' => 'user'), $this->userRoleEntityType);
+    $add_role_plugin = $this->actionManager->createInstance('user_add_role_action', $config);
 
-    $remove_role_plugin->execute($this->account);
+    $add_role_plugin->setContextValue('user', $this->account);
+    $add_role_plugin->execute();
   }
 
   /**
@@ -46,9 +45,10 @@ public function testExecuteAddNonExistingRole() {
       ->will($this->returnValue(FALSE));
 
     $config = array('rid' => 'test_role_1');
-    $remove_role_plugin = new AddRoleUser($config, 'user_remove_role_action', array('type' => 'user'), $this->userRoleEntityType);
+    $add_role_plugin = $this->actionManager->createInstance('user_add_role_action', $config);
 
-    $remove_role_plugin->execute($this->account);
+    $add_role_plugin->setContextValue('user', $this->account);
+    $add_role_plugin->execute();
   }
 
 }
diff --git a/core/modules/user/tests/src/Unit/Plugin/Action/RemoveRoleUserTest.php b/core/modules/user/tests/src/Unit/Plugin/Action/RemoveRoleUserTest.php
index e294398..146e508 100644
--- a/core/modules/user/tests/src/Unit/Plugin/Action/RemoveRoleUserTest.php
+++ b/core/modules/user/tests/src/Unit/Plugin/Action/RemoveRoleUserTest.php
@@ -7,8 +7,6 @@
 
 namespace Drupal\Tests\user\Unit\Plugin\Action;
 
-use Drupal\user\Plugin\Action\RemoveRoleUser;
-
 /**
  * @coversDefaultClass \Drupal\user\Plugin\Action\RemoveRoleUser
  * @group user
@@ -28,9 +26,10 @@ public function testExecuteRemoveExistingRole() {
       ->will($this->returnValue(TRUE));
 
     $config = array('rid' => 'test_role_1');
-    $remove_role_plugin = new RemoveRoleUser($config, 'user_remove_role_action', array('type' => 'user'), $this->userRoleEntityType);
+    $remove_role_plugin = $this->actionManager->createInstance('user_remove_role_action', $config);
 
-    $remove_role_plugin->execute($this->account);
+    $remove_role_plugin->setContextValue('user', $this->account);
+    $remove_role_plugin->execute();
   }
 
   /**
@@ -46,8 +45,9 @@ public function testExecuteRemoveNonExistingRole() {
       ->will($this->returnValue(FALSE));
 
     $config = array('rid' => 'test_role_1');
-    $remove_role_plugin = new RemoveRoleUser($config, 'user_remove_role_action', array('type' => 'user'), $this->userRoleEntityType);
+    $remove_role_plugin = $this->actionManager->createInstance('user_remove_role_action', $config);
 
+    $remove_role_plugin->setContextValue('user', $this->account);
     $remove_role_plugin->execute($this->account);
   }
 
diff --git a/core/modules/user/tests/src/Unit/Plugin/Action/RoleUserTestBase.php b/core/modules/user/tests/src/Unit/Plugin/Action/RoleUserTestBase.php
index 5f7ff13..b3127251 100644
--- a/core/modules/user/tests/src/Unit/Plugin/Action/RoleUserTestBase.php
+++ b/core/modules/user/tests/src/Unit/Plugin/Action/RoleUserTestBase.php
@@ -7,12 +7,12 @@
 
 namespace Drupal\Tests\user\Unit\Plugin\Action;
 
-use Drupal\Tests\UnitTestCase;
+use Drupal\Tests\Core\Action\ActionTestBase;
 
 /**
  * Provides a base class for user role action tests.
  */
-abstract class RoleUserTestBase extends UnitTestCase {
+abstract class RoleUserTestBase extends ActionTestBase {
 
   /**
    * The mocked account.
@@ -31,8 +31,9 @@
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  public function setUp() {
     parent::setUp();
+    $this->enableModule('user');
 
     $this->account = $this
       ->getMockBuilder('Drupal\user\Entity\User')
diff --git a/core/modules/user/tests/src/Unit/Plugin/views/field/UserBulkFormTest.php b/core/modules/user/tests/src/Unit/Plugin/views/field/UserBulkFormTest.php
index 0e0b44e..b4cc231 100644
--- a/core/modules/user/tests/src/Unit/Plugin/views/field/UserBulkFormTest.php
+++ b/core/modules/user/tests/src/Unit/Plugin/views/field/UserBulkFormTest.php
@@ -8,6 +8,8 @@
 namespace Drupal\Tests\user\Unit\Plugin\views\field;
 
 use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\Plugin\Context\ContextHandler;
 use Drupal\Tests\UnitTestCase;
 use Drupal\user\Plugin\views\field\UserBulkForm;
 
@@ -30,26 +32,44 @@ protected function tearDown() {
    * Tests the constructor assignment of actions.
    */
   public function testConstructor() {
-    $actions = array();
+    $action_configs = array();
 
     for ($i = 1; $i <= 2; $i++) {
-      $action = $this->getMock('\Drupal\system\ActionConfigEntityInterface');
+      $action = $this->getMock('\Drupal\Core\Action\ActionInterface');
       $action->expects($this->any())
-        ->method('getType')
-        ->will($this->returnValue('user'));
-      $actions[$i] = $action;
+        ->method('getPluginDefinition')
+        ->will($this->returnValue(array(
+          'context' => array(
+            'user' => new ContextDefinition('entity:user')
+          )
+        )));
+
+      $action_config = $this->getMock('\Drupal\system\ActionConfigEntityInterface');
+      $action_config->expects($this->any())
+        ->method('getPlugin')
+        ->will($this->returnValue($action));
+      $action_configs[$i] = $action_config;
     }
 
-    $action = $this->getMock('\Drupal\system\ActionConfigEntityInterface');
+    $action = $this->getMock('\Drupal\Core\Action\ActionInterface');
     $action->expects($this->any())
-      ->method('getType')
-      ->will($this->returnValue('node'));
-    $actions[] = $action;
+      ->method('getPluginDefinition')
+      ->will($this->returnValue(array(
+        'context' => array(
+          'node' => new ContextDefinition('entity:node')
+        )
+      )));
+
+    $action_config = $this->getMock('\Drupal\system\ActionConfigEntityInterface');
+    $action_config->expects($this->any())
+      ->method('getPlugin')
+      ->will($this->returnValue($action));
+    $action_configs[] = $action_config;
 
     $entity_storage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
     $entity_storage->expects($this->any())
       ->method('loadMultiple')
-      ->will($this->returnValue($actions));
+      ->will($this->returnValue($action_configs));
 
     $views_data = $this->getMockBuilder('Drupal\views\ViewsData')
       ->disableOriginalConstructor()
@@ -80,10 +100,10 @@ public function testConstructor() {
     $definition['title'] = '';
     $options = array();
 
-    $user_bulk_form = new UserBulkForm(array(), 'user_bulk_form', $definition, $entity_storage);
+    $user_bulk_form = new UserBulkForm(array(), 'user_bulk_form', $definition, $entity_storage, new ContextHandler());
     $user_bulk_form->init($executable, $display, $options);
 
-    $this->assertAttributeEquals(array_slice($actions, 0, -1, TRUE), 'actions', $user_bulk_form);
+    $this->assertAttributeEquals(array_slice($action_configs, 0, -1, TRUE), 'actions', $user_bulk_form);
   }
 
 }
diff --git a/core/modules/views/views.views.inc b/core/modules/views/views.views.inc
index 34167b0..cbf4c6c 100644
--- a/core/modules/views/views.views.inc
+++ b/core/modules/views/views.views.inc
@@ -6,7 +6,8 @@
  */
 
 use Drupal\Component\Utility\NestedArray;
-use Drupal\system\ActionConfigEntityInterface;
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
 
 /**
  * Implements hook_views_data().
@@ -139,21 +140,24 @@ function views_views_data() {
     }
   }
 
+  $context_handler = \Drupal::service('context.handler');
   // Registers an action bulk form per entity.
   foreach (\Drupal::entityManager()->getDefinitions() as $entity_type => $entity_info) {
-    $actions = array_filter(\Drupal::entityManager()->getStorage('action')->loadMultiple(), function (ActionConfigEntityInterface $action) use ($entity_type) {
-      return $action->getType() == $entity_type;
+    $match_context = array('context' => new Context(new ContextDefinition("entity:$entity_type")));
+    // Filter the actions to only include those that match for this entity type.
+    $actions = array_filter(\Drupal::entityManager()->getStorage('action')->loadMultiple(), function ($action) use ($context_handler, $match_context) {
+      $filtered = $context_handler->filterPluginDefinitionsByContexts($match_context, array($action->getPlugin()->getPluginDefinition()));
+      return !empty($filtered);
     });
-    if (empty($actions)) {
-      continue;
+    if (!empty($actions)) {
+      $data[$entity_info->getBaseTable()][$entity_type . '_bulk_form'] = array(
+        'title' => t('Bulk update'),
+        'help' => t('Allows users to apply an action to one or more items.'),
+        'field' => array(
+          'id' => 'bulk_form',
+        ),
+      );
     }
-    $data[$entity_info->getBaseTable()][$entity_type . '_bulk_form'] = array(
-      'title' => t('Bulk update'),
-      'help' => t('Allows users to apply an action to one or more items.'),
-      'field' => array(
-        'id' => 'bulk_form',
-      ),
-    );
   }
 
   // Registers views data for the entity itself.
diff --git a/core/tests/Drupal/Tests/Core/Action/ActionTestBase.php b/core/tests/Drupal/Tests/Core/Action/ActionTestBase.php
new file mode 100644
index 0000000..f26f2bf
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Action/ActionTestBase.php
@@ -0,0 +1,202 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Action\ActionTestBase.
+ */
+
+namespace Drupal\Tests\Core\Action;
+
+use Drupal\Core\Action\ActionManager;
+use Drupal\Core\Cache\NullBackend;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\TypedData\TypedDataManager;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Base class for action plugin tests.
+ *
+ * Action plugin tests leverage the real plugin managers to also test the
+ * content of the plugin annotations. Dependencies on  other 3rd party modules
+ * or APIs can and should be mocked; e.g. the action to delete an entity would
+ * mock the call to the entity API.
+ */
+abstract class ActionTestBase extends UnitTestCase {
+
+  /**
+   * The typed data manager.
+   *
+   * @var \Drupal\Core\TypedData\TypedDataManager
+   */
+  protected $typedDataManager;
+
+  /**
+   * The action manager.
+   *
+   * @var \Drupal\Core\Action\ActionManager
+   */
+  protected $actionManager;
+
+  /**
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
+   * All setup'ed namespaces.
+   *
+   * @var ArrayObject
+   */
+  protected $namespaces;
+
+  /**
+   * The cache backend.
+   *
+   * @var \Drupal\Core\Cache\NullBackend
+   */
+  protected $cacheBackend;
+
+  /**
+   * The mocked module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * Array object keyed by module names and TRUE as value.
+   *
+   * @var ArrayObject
+   */
+  protected $enabledModules;
+
+  /**
+   * The services container.
+   *
+   * @var \Drupal\Core\DependencyInjection\Container
+   */
+  protected $container;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    // We need to include this file manually since the function
+    // entity_get_bundles() will be called.
+    require_once $this->root . '/core/includes/entity.inc';
+
+    $this->enabledModules = new \ArrayObject();
+    $this->container = new ContainerBuilder();
+    // Register plugin managers used by Actions, but mock some unwanted
+    // dependencies requiring more stuff to loaded.
+    $this->moduleHandler = $this->getMockBuilder('Drupal\Core\Extension\ModuleHandlerInterface')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $this->moduleHandler->expects($this->any())
+      ->method('moduleExists')
+      ->will($this->returnCallback(function ($module) {
+        return [$module, $this->enabledModules[$module]];
+      }));
+
+    $this->cacheBackend = new NullBackend('action');
+    $this->namespaces = new \ArrayObject([
+      'Drupal\\Core\\TypedData' => $this->root . '/core/lib/Drupal/Core/TypedData',
+      'Drupal\\Core\\Validation' => $this->root . '/core/lib/Drupal/Core/Validation',
+      'Drupal\\Core\\Entity' => $this->root . '/core/lib/Drupal/Core/Entity',
+    ]);
+
+    $this->actionManager = new ActionManager($this->namespaces, $this->cacheBackend, $this->moduleHandler);
+    $this->typedDataManager = new TypedDataManager($this->namespaces, $this->cacheBackend, $this->moduleHandler);
+
+    $language = $this->getMock('Drupal\Core\Language\LanguageInterface');
+    $language->expects($this->any())
+      ->method('getId')
+      ->willReturn('en');
+
+    $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
+    $language_manager->expects($this->any())
+      ->method('getCurrentLanguage')
+      ->willReturn($language);
+    $language_manager->expects($this->any())
+      ->method('getLanguages')
+      ->willReturn([$language]);
+
+    $this->entityAccess = $this->getMock('Drupal\Core\Entity\EntityAccessControlHandlerInterface');
+
+    $this->entityManager = $this->getMockBuilder('Drupal\Core\Entity\EntityManager')
+      ->setMethods(['getAccessControlHandler'])
+      ->setConstructorArgs([
+        $this->namespaces,
+        $this->moduleHandler,
+        $this->cacheBackend,
+        $language_manager,
+        $this->getStringTranslationStub(),
+        $this->getClassResolverStub(),
+        $this->typedDataManager,
+        $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreInterface'),
+        $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface')
+      ])
+      ->getMock();
+
+    $this->entityManager->expects($this->any())
+      ->method('getAccessControlHandler')
+      ->with($this->anything())
+      ->will($this->returnValue($this->entityAccess));
+
+    $this->moduleHandler->expects($this->any())
+      ->method('getImplementations')
+      ->with('entity_type_build')
+      ->willReturn([]);
+
+    $this->container->set('plugin.manager.action', $this->actionManager);
+    $this->container->set('typed_data_manager', $this->typedDataManager);
+    $this->container->set('string_translation', $this->getStringTranslationStub());
+    $this->container->set('entity.manager', $this->entityManager);
+
+    \Drupal::setContainer($this->container);
+  }
+
+  /**
+   * Fakes the enabling of a module and loads its namespace.
+   *
+   * Default behaviour works fine for core modules.
+   *
+   * @param string $name
+   *   The name of the module that's gonna be enabled.
+   * @param array $namespaces
+   *   Map of the association between module's namespaces and filesystem paths.
+   */
+  protected function enableModule($name, array $namespaces = []) {
+    $this->enabledModules[$name] = TRUE;
+
+    if (empty($namespaces)) {
+      $namespaces = ['Drupal\\' . $name => $this->root . '/core/modules/' . $name . '/src'];
+    }
+    foreach ($namespaces as $namespace => $path) {
+      $this->namespaces[$namespace] = $path;
+    }
+  }
+
+  /**
+   * Returns a typed data object.
+   *
+   * This helper for quick creation of typed data objects.
+   *
+   * @param string $data_type
+   *   The data type to create an object for.
+   * @param mixed[] $value
+   *   The value to set.
+   *
+   * @return \Drupal\Core\TypedData\TypedDataInterface
+   *   The created object.
+   */
+  protected function getTypedData($data_type, $value)  {
+    $definition = $this->typedDataManager->createDataDefinition($data_type);
+    $data = $this->typedDataManager->create($definition);
+    $data->setValue($value);
+    return $data;
+  }
+
+}
