diff --git a/core/modules/action/action.views.inc b/core/modules/action/action.views.inc
deleted file mode 100644
index b38eead..0000000
--- a/core/modules/action/action.views.inc
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-/**
- * @file
- * Provides views data for action.module.
- */
-
-/**
- * Implements hook_views_data().
- *
- * @todo hook_views_data() is used instead of hook_views_data_alter(), because
- *   the alter hook doesn't load the *.views.inc automatically.
- */
-function action_views_data() {
-  $data['action']['table']['group'] = t('Action');
-  $data['action']['table']['join'] = array(
-    '#global' => array(),
-  );
-  $data['action']['action_bulk_form'] = array(
-    'title' => t('Bulk update'),
-    'help' => t('Allows users to apply an action to one or more items.'),
-    'field' => array(
-      'id' => 'action_bulk_form',
-    ),
-  );
-  return $data;
-}
diff --git a/core/modules/action/lib/Drupal/action/Tests/BulkFormTest.php b/core/modules/action/lib/Drupal/action/Tests/BulkFormTest.php
index dcce0c7..0e6f98d 100644
--- a/core/modules/action/lib/Drupal/action/Tests/BulkFormTest.php
+++ b/core/modules/action/lib/Drupal/action/Tests/BulkFormTest.php
@@ -58,8 +58,8 @@ public function testBulkForm() {
     // Make sure a checkbox appears on all rows.
     $edit = array();
     for ($i = 0; $i < 10; $i++) {
-      $this->assertFieldById('edit-action-bulk-form-' . $i, NULL, format_string('The checkbox on row @row appears.', array('@row' => $i)));
-      $edit["action_bulk_form[$i]"] = TRUE;
+      $this->assertFieldById('edit-node-bulk-form-' . $i, NULL, format_string('The checkbox on row @row appears.', array('@row' => $i)));
+      $edit["node_bulk_form[$i]"] = TRUE;
     }
 
     // Set all nodes to sticky and check that.
@@ -77,7 +77,7 @@ public function testBulkForm() {
     $node = node_load($nodes[0]->id());
     $this->assertTrue($node->isPublished(), 'The node is published.');
 
-    $edit = array('action_bulk_form[0]' => TRUE, 'action' => 'node_unpublish_action');
+    $edit = array('node_bulk_form[0]' => TRUE, 'action' => 'node_unpublish_action');
     $this->drupalPostForm(NULL, $edit, t('Apply'));
 
     $this->assertText('Unpublish content was applied to 1 item.');
@@ -93,9 +93,9 @@ public function testBulkForm() {
     // Set up to include just the sticky actions.
     $view = views_get_view('test_bulk_form');
     $display = &$view->storage->getDisplay('default');
-    $display['display_options']['fields']['action_bulk_form']['include_exclude'] = 'include';
-    $display['display_options']['fields']['action_bulk_form']['selected_actions']['node_make_sticky_action'] = 'node_make_sticky_action';
-    $display['display_options']['fields']['action_bulk_form']['selected_actions']['node_make_unsticky_action'] = 'node_make_unsticky_action';
+    $display['display_options']['fields']['node_bulk_form']['include_exclude'] = 'include';
+    $display['display_options']['fields']['node_bulk_form']['selected_actions']['node_make_sticky_action'] = 'node_make_sticky_action';
+    $display['display_options']['fields']['node_bulk_form']['selected_actions']['node_make_unsticky_action'] = 'node_make_unsticky_action';
     $view->save();
 
     $this->drupalGet('test_bulk_form');
@@ -107,7 +107,7 @@ public function testBulkForm() {
     // Set up to exclude the sticky actions.
     $view = views_get_view('test_bulk_form');
     $display = &$view->storage->getDisplay('default');
-    $display['display_options']['fields']['action_bulk_form']['include_exclude'] = 'exclude';
+    $display['display_options']['fields']['node_bulk_form']['include_exclude'] = 'exclude';
     $view->save();
 
     $this->drupalGet('test_bulk_form');
@@ -122,7 +122,7 @@ public function testBulkForm() {
     // Setup up a different bulk form title.
     $view = views_get_view('test_bulk_form');
     $display = &$view->storage->getDisplay('default');
-    $display['display_options']['fields']['action_bulk_form']['action_title'] = 'Test title';
+    $display['display_options']['fields']['node_bulk_form']['action_title'] = 'Test title';
     $view->save();
 
     $this->drupalGet('test_bulk_form');
diff --git a/core/modules/action/tests/action_bulk_test/config/views.view.test_bulk_form.yml b/core/modules/action/tests/action_bulk_test/config/views.view.test_bulk_form.yml
index ff05d91..fd41bc4 100644
--- a/core/modules/action/tests/action_bulk_test/config/views.view.test_bulk_form.yml
+++ b/core/modules/action/tests/action_bulk_test/config/views.view.test_bulk_form.yml
@@ -35,7 +35,7 @@ display:
           summary: ''
           columns:
             title: title
-            action_bulk_form: action_bulk_form
+            node_bulk_form: node_bulk_form
           info:
             title:
               sortable: false
@@ -73,10 +73,10 @@ display:
           link_to_node: true
           plugin_id: node
           provider: node
-        action_bulk_form:
-          id: action_bulk_form
-          table: action
-          field: action_bulk_form
+        node_bulk_form:
+          id: node_bulk_form
+          table: node
+          field: node_bulk_form
           relationship: none
           group_type: group
           admin_label: ''
@@ -121,8 +121,8 @@ display:
           hide_empty: false
           empty_zero: false
           hide_alter_empty: true
-          plugin_id: action_bulk_form
-          provider: action
+          plugin_id: node_bulk_form
+          provider: node
       filters:
         status:
           value: true
diff --git a/core/modules/node/lib/Drupal/node/Plugin/views/field/NodeBulkForm.php b/core/modules/node/lib/Drupal/node/Plugin/views/field/NodeBulkForm.php
index 35d6720..2821c38 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/views/field/NodeBulkForm.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/views/field/NodeBulkForm.php
@@ -8,7 +8,7 @@
 namespace Drupal\node\Plugin\views\field;
 
 use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\views\Plugin\views\field\ActionBulkForm;
+use Drupal\system\Plugin\views\field\BulkForm;
 use Drupal\Core\Cache\Cache;
 
 /**
@@ -16,38 +16,24 @@
  *
  * @PluginID("node_bulk_form")
  */
-class NodeBulkForm extends ActionBulkForm {
-
-  /**
-   * Constructs a new NodeBulkForm object.
-   */
-  public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityManagerInterface $manager) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition, $manager);
-
-    // Filter the actions to only include those for the 'node' entity type.
-    $this->actions = array_filter($this->actions, function ($action) {
-      return $action->getType() == 'node';
-    });
-  }
+class NodeBulkForm extends BulkForm {
 
   /**
    * {@inheritdoc}
    */
-  public function viewsFormValidate(&$form, &$form_state) {
-    $selected = array_filter($form_state['values'][$this->options['id']]);
-    if (empty($selected)) {
-      form_set_error('', $form_state, t('No items selected.'));
+  public function viewsFormSubmit(&$form, &$form_state) {
+    parent::viewsFormSubmit($form, $form_state);
+
+    if ($form_state['step'] == 'views_form_views_form') {
+      Cache::invalidateTags(array('content' => TRUE));
     }
   }
 
   /**
    * {@inheritdoc}
    */
-  public function viewsFormSubmit(&$form, &$form_state) {
-    parent::viewsFormSubmit($form, $form_state);
-    if ($form_state['step'] == 'views_form_views_form') {
-      Cache::invalidateTags(array('content' => TRUE));
-    }
+  protected function emptySelectedMessage() {
+    return t('No content selected.');
   }
 
 }
diff --git a/core/modules/node/node.views.inc b/core/modules/node/node.views.inc
index cdeb8a0..e990571 100644
--- a/core/modules/node/node.views.inc
+++ b/core/modules/node/node.views.inc
@@ -206,14 +206,6 @@ function node_views_data() {
     );
   }
 
-  $data['node']['node_bulk_form'] = array(
-    'title' => t('Node operations bulk form'),
-    'help' => t('Add a form element that lets you run operations on multiple nodes.'),
-    'field' => array(
-      'id' => 'node_bulk_form',
-    ),
-  );
-
   $data['node']['view_node'] = array(
     'field' => array(
       'title' => t('Link to content'),
@@ -631,6 +623,19 @@ function node_views_data() {
 }
 
 /**
+ * Implements hook_views_data_alter().
+ */
+function node_views_data_alter(&$data) {
+  $data['node']['node_bulk_form'] = array(
+    'title' => t('Node operations bulk form'),
+    'help' => t('Add a form element that lets you run operations on multiple nodes.'),
+    'field' => array(
+      'id' => 'node_bulk_form',
+    ),
+  );
+}
+
+/**
  * Implements hook_preprocess_node().
  */
 function node_row_node_view_preprocess_node(&$variables) {
diff --git a/core/modules/node/tests/Drupal/node/Tests/Plugin/views/field/NodeBulkFormTest.php b/core/modules/node/tests/Drupal/node/Tests/Plugin/views/field/NodeBulkFormTest.php
index aec235c..7e1a95e 100644
--- a/core/modules/node/tests/Drupal/node/Tests/Plugin/views/field/NodeBulkFormTest.php
+++ b/core/modules/node/tests/Drupal/node/Tests/Plugin/views/field/NodeBulkFormTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\node\Tests\Plugin\views\field;
 
+use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\node\Plugin\views\field\NodeBulkForm;
 use Drupal\Tests\UnitTestCase;
 
@@ -26,40 +27,70 @@ public static function getInfo() {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
    * Tests the constructor assignment of actions.
    */
   public function testConstructor() {
     $actions = array();
 
     for ($i = 1; $i <= 2; $i++) {
-      $action = $this->getMockBuilder('Drupal\system\Entity\Action')
-        ->disableOriginalConstructor()
-        ->getMock();
+      $action = $this->getMock('\Drupal\system\ActionConfigEntityInterface');
       $action->expects($this->any())
         ->method('getType')
         ->will($this->returnValue('node'));
       $actions[$i] = $action;
     }
 
-    $action = $this->getMockBuilder('Drupal\system\Entity\Action')
-      ->disableOriginalConstructor()
-      ->getMock();
+    $action = $this->getMock('\Drupal\system\ActionConfigEntityInterface');
     $action->expects($this->any())
       ->method('getType')
       ->will($this->returnValue('user'));
     $actions[] = $action;
 
-    $entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
     $storage_controller = $this->getMock('Drupal\Core\Entity\EntityStorageControllerInterface');
     $storage_controller->expects($this->any())
       ->method('loadMultiple')
       ->will($this->returnValue($actions));
 
-    $entity_manager->expects($this->any())
-      ->method('getStorageController')
-      ->with('action')
-      ->will($this->returnValue($storage_controller));
-    $node_bulk_form = new NodeBulkForm(array(), 'node_bulk_form', array(), $entity_manager);
+    $views_data = $this->getMockBuilder('Drupal\views\ViewsData')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $views_data->expects($this->any())
+      ->method('get')
+      ->with('node')
+      ->will($this->returnValue(array('table' => array('entity type' => 'node'))));
+    $container = new ContainerBuilder();
+    $container->set('views.views_data', $views_data);
+    \Drupal::setContainer($container);
+
+    $storage = $this->getMock('Drupal\views\ViewStorageInterface');
+    $storage->expects($this->any())
+      ->method('get')
+      ->with('base_table')
+      ->will($this->returnValue('node'));
+
+    $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $executable->storage = $storage;
+
+    $display = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $definition['title'] = '';
+    $options = array();
+
+    $node_bulk_form = new NodeBulkForm(array(), 'node_bulk_form', $definition, $storage_controller);
+    $node_bulk_form->init($executable, $display, $options);
 
     $this->assertAttributeEquals(array_slice($actions, 0, -1, TRUE), 'actions', $node_bulk_form);
   }
diff --git a/core/modules/system/lib/Drupal/system/Plugin/views/field/BulkFormBase.php b/core/modules/system/lib/Drupal/system/Plugin/views/field/BulkForm.php
similarity index 59%
rename from core/modules/system/lib/Drupal/system/Plugin/views/field/BulkFormBase.php
rename to core/modules/system/lib/Drupal/system/Plugin/views/field/BulkForm.php
index ceee2e2..3b39459 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/views/field/BulkFormBase.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/views/field/BulkForm.php
@@ -2,21 +2,32 @@
 
 /**
  * @file
- * Contains \Drupal\system\Plugin\views\field\BulkFormBase.
+ * Contains \Drupal\system\Plugin\views\field\BulkForm.
  */
 
 namespace Drupal\system\Plugin\views\field;
 
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\Plugin\views\style\Table;
 use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * Defines a generic bulk operation form element.
+ * Defines a actions-based bulk operation form element.
+ *
+ * @PluginID("bulk_form")
  */
-abstract class BulkFormBase extends FieldPluginBase {
+class BulkForm extends FieldPluginBase {
+
+  /**
+   * The action storage controller.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
+   */
+  protected $actionStorage;
 
   /**
    * An array of actions that can be executed.
@@ -26,11 +37,55 @@
   protected $actions = array();
 
   /**
+   * Constructs a new BulkForm object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin ID for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage
+   *   The action storage controller.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityStorageControllerInterface $storage) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->actionStorage = $storage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
+    return new static($configuration, $plugin_id, $plugin_definition, $container->get('entity.manager')->getStorageController('action'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
+    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;
+    });
+  }
+
+  /**
    * {@inheritdoc }
    */
   protected function defineOptions() {
     $options = parent::defineOptions();
     $options['action_title'] = array('default' => 'With selection', 'translatable' => TRUE);
+    $options['include_exclude'] = array(
+      'default' => 'exclude',
+    );
+    $options['selected_actions'] = array(
+      'default' => array(),
+    );
     return $options;
   }
 
@@ -45,33 +100,32 @@ public function buildOptionsForm(&$form, &$form_state) {
       '#description' => t('The title shown above the actions dropdown.'),
     );
 
-    parent::buildOptionsForm($form, $form_state);
-  }
-
-
-  /**
-   * Constructs a new BulkForm object.
-   *
-   * @param array $configuration
-   *   A configuration array containing information about the plugin instance.
-   * @param string $plugin_id
-   *   The plugin ID for the plugin instance.
-   * @param array $plugin_definition
-   *   The plugin implementation definition.
-   * @param \Drupal\Core\Entity\EntityManagerInterface $manager
-   *   The entity manager.
-   */
-  public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityManagerInterface $manager) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $form['include_exclude'] = array(
+      '#type' => 'radios',
+      '#title' => t('Available actions'),
+      '#options' => array(
+        'exclude' => t('All actions, except selected'),
+        'include' => t('Only selected actions'),
+      ),
+      '#default_value' => $this->options['include_exclude'],
+    );
+    $form['selected_actions'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Selected actions'),
+      '#options' => $this->getBulkOptions(FALSE),
+      '#default_value' => $this->options['selected_actions'],
+    );
 
-    $this->actions = $manager->getStorageController('action')->loadMultiple();
+    parent::buildOptionsForm($form, $form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
-    return new static($configuration, $plugin_id, $plugin_definition, $container->get('entity.manager'));
+  public function validateOptionsForm(&$form, &$form_state) {
+    parent::validateOptionsForm($form, $form_state);
+
+    $form_state['values']['options']['selected_actions'] = array_filter($form_state['values']['options']['selected_actions']);
   }
 
   /**
@@ -97,6 +151,7 @@ public function preRender(&$values) {
     }
   }
 
+
   /**
    * Form constructor for the bulk form.
    *
@@ -156,13 +211,33 @@ public function viewsForm(&$form, &$form_state) {
   /**
    * Returns the available operations for this form.
    *
+   * @param bool $filtered
+   *   (optional) Whether to filter actions to selected actions.
    * @return array
    *   An associative array of operations, suitable for a select element.
    */
-  protected function getBulkOptions() {
-    return array_map(function ($action) {
-      return $action->label();
-    }, $this->actions);
+  protected function getBulkOptions($filtered = TRUE) {
+    $options = array();
+    // Filter the action list.
+    foreach ($this->actions as $id => $action) {
+      if ($filtered) {
+        $in_selected = in_array($id, $this->options['selected_actions']);
+        // If the field is configured to include only the selected actions,
+        // skip actions that were not selected.
+        if (($this->options['include_exclude'] == 'include') && !$in_selected) {
+          continue;
+        }
+        // Otherwise, if the field is configured to exclude the selected
+        // actions, skip actions that were selected.
+        elseif (($this->options['include_exclude'] == 'exclude') && $in_selected) {
+          continue;
+        }
+      }
+
+      $options[$id] = $action->label();
+    }
+
+    return $options;
   }
 
   /**
@@ -190,6 +265,35 @@ public function viewsFormSubmit(&$form, &$form_state) {
       if (!empty($operation_definition['confirm_form_path'])) {
         $form_state['redirect'] = $operation_definition['confirm_form_path'];
       }
+
+      $count = count(array_filter($form_state['values'][$this->options['id']]));
+      $action = $this->actions[$form_state['values']['action']];
+      if ($count) {
+        drupal_set_message($this->translationManager()->formatPlural($count, '%action was applied to @count item.', '%action was applied to @count items.', array(
+          '%action' => $action->label(),
+        )));
+      }
+
+    }
+  }
+
+  /**
+   * Returns the message to be displayed when there are no selected items.
+   *
+   * @return string
+   *  Message displayed when no items are selected.
+   */
+  protected function emptySelectedMessage() {
+    return t('No items selected.');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function viewsFormValidate(&$form, &$form_state) {
+    $selected = array_filter($form_state['values'][$this->options['id']]);
+    if (empty($selected)) {
+      form_set_error('', $form_state, $this->emptySelectedMessage());
     }
   }
 
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/field/UserBulkForm.php b/core/modules/user/lib/Drupal/user/Plugin/views/field/UserBulkForm.php
index b548cd5..8f6c38c 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/field/UserBulkForm.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/field/UserBulkForm.php
@@ -8,29 +8,15 @@
 namespace Drupal\user\Plugin\views\field;
 
 use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\views\Plugin\views\field\ActionBulkForm;
+use Drupal\system\Plugin\views\field\BulkForm;
 use Drupal\user\UserInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Defines a user operations bulk form element.
  *
  * @PluginID("user_bulk_form")
  */
-class UserBulkForm extends ActionBulkForm {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityManagerInterface $manager) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition, $manager);
-
-    // Filter the actions to only include those for the 'user' entity type.
-    $this->actions = array_filter($this->actions, function ($action) {
-      return $action->getType() == 'user';
-    });
-
-  }
+class UserBulkForm extends BulkForm {
 
   /**
    * {@inheritdoc}
@@ -53,11 +39,8 @@ public function viewsForm(&$form, &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function viewsFormValidate(&$form, &$form_state) {
-    $selected = array_filter($form_state['values'][$this->options['id']]);
-    if (empty($selected)) {
-      form_set_error('', $form_state, t('No users selected.'));
-    }
+  protected function emptySelectedMessage() {
+    return t('No users selected.');
   }
 
 }
diff --git a/core/modules/user/tests/Drupal/user/Tests/Plugin/views/field/UserBulkFormTest.php b/core/modules/user/tests/Drupal/user/Tests/Plugin/views/field/UserBulkFormTest.php
index 74897b3..5f8ec1f 100644
--- a/core/modules/user/tests/Drupal/user/Tests/Plugin/views/field/UserBulkFormTest.php
+++ b/core/modules/user/tests/Drupal/user/Tests/Plugin/views/field/UserBulkFormTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Tests\Plugin\views\field;
 
+use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Tests\UnitTestCase;
 use Drupal\user\Plugin\views\field\UserBulkForm;
 
@@ -26,41 +27,70 @@ public static function getInfo() {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
    * Tests the constructor assignment of actions.
    */
   public function testConstructor() {
     $actions = array();
 
     for ($i = 1; $i <= 2; $i++) {
-      $action = $this->getMockBuilder('Drupal\system\Entity\Action')
-        ->disableOriginalConstructor()
-        ->getMock();
+      $action = $this->getMock('\Drupal\system\ActionConfigEntityInterface');
       $action->expects($this->any())
         ->method('getType')
         ->will($this->returnValue('user'));
       $actions[$i] = $action;
     }
 
-    $action = $this->getMockBuilder('Drupal\system\Entity\Action')
-      ->disableOriginalConstructor()
-      ->getMock();
+    $action = $this->getMock('\Drupal\system\ActionConfigEntityInterface');
     $action->expects($this->any())
       ->method('getType')
       ->will($this->returnValue('node'));
     $actions[] = $action;
 
-    $entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
     $storage_controller = $this->getMock('Drupal\Core\Entity\EntityStorageControllerInterface');
     $storage_controller->expects($this->any())
       ->method('loadMultiple')
       ->will($this->returnValue($actions));
 
-    $entity_manager->expects($this->any())
-      ->method('getStorageController')
-      ->with('action')
-      ->will($this->returnValue($storage_controller));
+    $views_data = $this->getMockBuilder('Drupal\views\ViewsData')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $views_data->expects($this->any())
+      ->method('get')
+      ->with('users')
+      ->will($this->returnValue(array('table' => array('entity type' => 'user'))));
+    $container = new ContainerBuilder();
+    $container->set('views.views_data', $views_data);
+    \Drupal::setContainer($container);
+
+    $storage = $this->getMock('Drupal\views\ViewStorageInterface');
+    $storage->expects($this->any())
+      ->method('get')
+      ->with('base_table')
+      ->will($this->returnValue('users'));
+
+    $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $executable->storage = $storage;
+
+    $display = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $definition['title'] = '';
+    $options = array();
 
-    $user_bulk_form = new UserBulkForm(array(), 'user_bulk_form', array(), $entity_manager);
+    $user_bulk_form = new UserBulkForm(array(), 'user_bulk_form', $definition, $storage_controller);
+    $user_bulk_form->init($executable, $display, $options);
 
     $this->assertAttributeEquals(array_slice($actions, 0, -1, TRUE), 'actions', $user_bulk_form);
   }
diff --git a/core/modules/user/user.views.inc b/core/modules/user/user.views.inc
index 45a76d0..d3ddf92 100644
--- a/core/modules/user/user.views.inc
+++ b/core/modules/user/user.views.inc
@@ -317,14 +317,6 @@ function user_views_data() {
     ),
   );
 
-  $data['users']['user_bulk_form'] = array(
-    'title' => t('Bulk update'),
-    'help' => t('Add a form element that lets you run operations on multiple users.'),
-    'field' => array(
-      'id' => 'user_bulk_form',
-    ),
-  );
-
   // Define the base group of this table. Fields that don't have a group defined
   // will go into this field by default.
   $data['users_roles']['table']['group']  = t('User');
@@ -375,6 +367,20 @@ function user_views_data() {
 }
 
 /**
+ * Implements hook_views_data_alter().
+ */
+function user_views_data_alter(&$data) {
+  $data['users']['user_bulk_form'] = array(
+    'title' => t('Bulk update'),
+    'help' => t('Add a form element that lets you run operations on multiple users.'),
+    'field' => array(
+      'id' => 'user_bulk_form',
+    ),
+  );
+}
+
+
+/**
  * Implements hook_views_plugins_row_alter().
  *
  * Replaces the generic row plugin by a custom one for users.
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
index 1b8c4ce..fd70314 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
@@ -721,7 +721,7 @@ public function getEntityType() {
       return $views_data['table']['entity type'];
     }
     else {
-      throw new \Exception(format_string('No entity type for field @field on view @view', array('@field' => $this->options['id'], '@view' => $this->view->storage->id())));
+      throw new \Exception(String::format('No entity type for field @field on view @view', array('@field' => $this->options['id'], '@view' => $this->view->storage->id())));
     }
   }
 
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/field/ActionBulkForm.php b/core/modules/views/lib/Drupal/views/Plugin/views/field/ActionBulkForm.php
deleted file mode 100644
index 8932037..0000000
--- a/core/modules/views/lib/Drupal/views/Plugin/views/field/ActionBulkForm.php
+++ /dev/null
@@ -1,115 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\views\Plugin\views\field\BulkForm.
- */
-
-namespace Drupal\views\Plugin\views\field;
-
-use Drupal\system\Plugin\views\field\BulkFormBase;
-
-/**
- * Defines a actions-based bulk operation form element.
- *
- * @PluginID("action_bulk_form")
- */
-class ActionBulkForm extends BulkFormBase {
-
-  /**
-   * Overrides \Drupal\views\Plugin\views\field\FieldPluginBase::defineOptions().
-   */
-  protected function defineOptions() {
-    $options = parent::defineOptions();
-    $options['include_exclude'] = array(
-      'default' => 'exclude',
-    );
-    $options['selected_actions'] = array(
-      'default' => array(),
-    );
-    return $options;
-  }
-
-  /**
-   * Overrides \Drupal\views\Plugin\views\field\FieldPluginBase::buildOptionsForm().
-   */
-  public function buildOptionsForm(&$form, &$form_state) {
-    parent::buildOptionsForm($form, $form_state);
-
-    $form['include_exclude'] = array(
-      '#type' => 'radios',
-      '#title' => t('Available actions'),
-      '#options' => array(
-        'exclude' => t('All actions, except selected'),
-        'include' => t('Only selected actions'),
-      ),
-      '#default_value' => $this->options['include_exclude'],
-    );
-    $form['selected_actions'] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('Selected actions'),
-      '#options' => $this->getBulkOptions(FALSE),
-      '#default_value' => $this->options['selected_actions'],
-    );
-  }
-
-  /**
-   * Overrides \Drupal\views\Plugin\views\PluginBase::buildOptionsForm().
-   */
-  public function validateOptionsForm(&$form, &$form_state) {
-    parent::validateOptionsForm($form, $form_state);
-
-    $form_state['values']['options']['selected_actions'] = array_filter($form_state['values']['options']['selected_actions']);
-  }
-
-  /**
-   * Implements \Drupal\system\Plugin\views\field\BulkFormBase::getBulkOptions().
-   *
-   * @param bool $filtered
-   *   (optional) Whether to filter actions to selected actions.
-   */
-  protected function getBulkOptions($filtered = TRUE) {
-    // Get all available actions.
-    $entity_type = $this->getEntityType();
-    $options = array();
-    // Filter the action list.
-    foreach ($this->actions as $id => $action) {
-      if ($filtered) {
-        $in_selected = in_array($id, $this->options['selected_actions']);
-        // If the field is configured to include only the selected actions,
-        // skip actions that were not selected.
-        if (($this->options['include_exclude'] == 'include') && !$in_selected) {
-          continue;
-        }
-        // Otherwise, if the field is configured to exclude the selected
-        // actions, skip actions that were selected.
-        elseif (($this->options['include_exclude'] == 'exclude') && $in_selected) {
-          continue;
-        }
-      }
-      // Only allow actions that are valid for this entity type.
-      if (($action->getType() == $entity_type)) {
-        $options[$id] = $action->label();
-      }
-    }
-
-    return $options;
-  }
-
-  /**
-   * Implements \Drupal\system\Plugin\views\field\BulkFormBase::viewsFormSubmit().
-   */
-  public function viewsFormSubmit(&$form, &$form_state) {
-    parent::viewsFormSubmit($form, $form_state);
-    if ($form_state['step'] == 'views_form_views_form') {
-      $count = count(array_filter($form_state['values'][$this->options['id']]));
-      $action = $this->actions[$form_state['values']['action']];
-      if ($count) {
-        drupal_set_message(format_plural($count, '%action was applied to @count item.', '%action was applied to @count items.', array(
-          '%action' => $action->label(),
-        )));
-      }
-    }
-  }
-
-}
diff --git a/core/modules/views/views.views.inc b/core/modules/views/views.views.inc
index c7bbf05..66e30fd 100644
--- a/core/modules/views/views.views.inc
+++ b/core/modules/views/views.views.inc
@@ -5,6 +5,8 @@
  * Provide views data that isn't tied to any other module.
  */
 
+use Drupal\system\ActionConfigEntityInterface;
+
 /**
  * Implements hook_views_data().
  */
@@ -128,5 +130,21 @@ function views_views_data() {
     }
   }
 
+  // Registers an action bulk form per entity.
+  foreach (\Drupal::entityManager()->getDefinitions() as $entity_type => $entity_info) {
+    $actions = array_filter(\Drupal::entityManager()->getStorageController('action')->loadMultiple(), function (ActionConfigEntityInterface $action) use ($entity_type) {
+      return $action->getType() == $entity_type;
+    });
+    if (empty($actions)) {
+      continue;
+    }
+    $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',
+      ),
+    );
+  }
   return $data;
 }
