diff --git a/core/modules/action/action.views.inc b/core/modules/action/action.views.inc
new file mode 100644
index 0000000..847096b
--- /dev/null
+++ b/core/modules/action/action.views.inc
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @file
+ * Provides views data and handlers for action.module.
+ *
+ * @ingroup views_module_handlers
+ */
+
+/**
+ * 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['views']['action_bulk_form'] = array(
+    'title' => t('Actions bulk form'),
+    'help' => t('Add a form element that lets you apply actions to multiple items.'),
+    'field' => array(
+      'id' => 'action_bulk_form',
+    ),
+  );
+
+  return $data;
+}
+
+/**
+ * Implements hook_views_form_substitutions().
+ */
+function action_views_form_substitutions() {
+  // Views check_plains the column label, so by doing it matches for the
+  // replacement.
+  $select_all_placeholder = check_plain('<!--action-bulk-form-select-all-->');
+  $select_all = array(
+    '#type' => 'checkbox',
+    '#default_value' => FALSE,
+    '#attributes' => array('class' => array('action-table-select-all')),
+  );
+
+  return array(
+    $select_all_placeholder => drupal_render($select_all),
+  );
+}
diff --git a/core/modules/action/lib/Drupal/action/Plugin/views/field/BulkForm.php b/core/modules/action/lib/Drupal/action/Plugin/views/field/BulkForm.php
new file mode 100644
index 0000000..278bfc0
--- /dev/null
+++ b/core/modules/action/lib/Drupal/action/Plugin/views/field/BulkForm.php
@@ -0,0 +1,110 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\action\Plugin\views\field\BulkForm.
+ */
+
+namespace Drupal\action\Plugin\views\field;
+
+use Drupal\Core\Annotation\Plugin;
+use Drupal\views\Plugin\views\field\FieldPluginBase;
+
+/**
+ * Defines a simple bulk operation form element.
+ *
+ * @Plugin(
+ *   id = "action_bulk_form",
+ *   module = "action"
+ * )
+ */
+class BulkForm extends FieldPluginBase {
+
+  /**
+   * Overrides \Drupal\views\Plugin\views\Plugin\field\FieldPluginBase::render().
+   */
+  public function render($values) {
+    return '<!--form-item-' . $this->options['id'] . '--' . $this->view->row_index . '-->';
+  }
+
+  /**
+   * Overrides \Drupal\views\Plugin\views\Plugin\field\FieldPluginBase::pre_render().
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+
+    // If the view is using a table style, provide a placeholder for a
+    // "select all" checkbox.
+    if (!empty($this->view->style_plugin) && $this->view->style_plugin instanceof \Drupal\views\Plugin\views\style\Table) {
+      // Add the tableselect css classes.
+      $this->options['element_label_class'] .= 'select-all';
+      // Hide the actual label of the field on the table header.
+      $this->options['label'] = '';
+    }
+  }
+
+  /**
+   * Implements \Drupal\views\Plugin\views\Plugin\field\FieldPluginBase::views_form().
+   */
+  public function views_form(&$form, &$form_state) {
+    // Add the tableselect javascript.
+    $form['#attached']['library'][] = array('system', 'drupal.tableselect');
+    // Render checkboxes for all rows.
+    foreach ($this->view->result as $row_index => $row) {
+      $entity_id = $this->get_value($row);
+
+      $form[$this->options['id']][$row_index] = array(
+        '#type' => 'checkbox',
+        '#return_value' => $entity_id,
+        '#default_value' => FALSE,
+      );
+    }
+
+    // Get all available actions.
+    $actions = action_get_all_actions();
+    $entity_type = $this->getEntityType();
+    // Filter actions by the entity type and build options for the form.
+    $actions = array_filter($actions, function($action) use ($entity_type) {
+      return $action['type'] == $entity_type && empty($action['configurable']);
+    });
+    $options = array_map(function($action) {
+      return $action['label'];
+    }, $actions);
+
+    $form['action'] = array(
+      '#type' => 'select',
+      '#title' => t('Action'),
+      '#options' => $options,
+      '#description' => t('Select the action you want to execute on the content entitites.'),
+    );
+
+    // Move the submit button beside the selection.
+    $form['actions']['#weight'] = 1;
+
+      // Replace the text with Update.
+    $form['actions']['submit']['#value'] = t('Update');
+  }
+
+  /**
+   * Implements \Drupal\views\Plugin\views\Plugin\field\FieldPluginBase::views_form_submit().
+   */
+  public function views_form_submit(&$form, &$form_state) {
+    if ($form_state['step'] == 'views_form_views_form') {
+      $action = $form_state['values']['action'];
+      $action = action_load($action);
+
+      foreach ($this->view->result as $row) {
+        $entity = $this->get_entity($row);
+        actions_do($action->aid, $entity);
+        $entity->save();
+      }
+    }
+  }
+
+  /**
+   * Overrides \Drupal\views\Plugin\views\Plugin\field\FieldPluginBase::query().
+   */
+  public function query() {
+  }
+
+}
diff --git a/core/modules/action/lib/Drupal/action/Tests/BulkFormTest.php b/core/modules/action/lib/Drupal/action/Tests/BulkFormTest.php
new file mode 100644
index 0000000..7262e6e
--- /dev/null
+++ b/core/modules/action/lib/Drupal/action/Tests/BulkFormTest.php
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\action\Tests\BulkFormTest.
+ */
+
+namespace Drupal\action\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests the views bulk form test.
+ *
+ * @see \Drupal\action\Plugin\views\field\BulkForm
+ */
+class BulkFormTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('action_bulk_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Bulk form',
+      'description' => 'Tests the views bulk form test.',
+      'group' => 'Action',
+    );
+  }
+
+  /**
+   * Tests the bulk form.
+   */
+  public function testBulkForm() {
+    $nodes = array();
+    for ($i = 0; $i < 10; $i++) {
+      $nodes[] = $this->drupalCreateNode(array('sticky' => FALSE));
+    }
+
+    $this->drupalGet('test_bulk_form');
+
+    $this->assertFieldById('edit-action', NULL, 'The action select field appears.');
+
+    // Make sure a checkbox appears on all rows.
+    $edit = array();
+    for ($i = 0; $i < 10; $i++) {
+      $this->assertFieldById('edit-' . $i, NULL, format_string('The checkbox on row @row appears.', array('@row' => $i)));
+      $edit[$i] = 'on';
+    }
+
+    // Set all nodes to sticky and check that.
+    $edit += array('action' => 'node_make_sticky_action');
+    $this->drupalPost(NULL, $edit, t('Update'));
+
+    foreach ($nodes as $node) {
+      $changed_node = node_load($node->id());
+      $this->assertTrue($changed_node->sticky, format_string('Node @nid got marked as sticky.', array('@nid' => $node->id())));
+    }
+  }
+
+}
diff --git a/core/modules/action/tests/action_bulk_test/action_bulk_test.info b/core/modules/action/tests/action_bulk_test/action_bulk_test.info
new file mode 100644
index 0000000..3698370
--- /dev/null
+++ b/core/modules/action/tests/action_bulk_test/action_bulk_test.info
@@ -0,0 +1,8 @@
+name = Action bulk form test
+description = Support module for action bulk form testing.
+package = Testing
+version = VERSION
+core = 8.x
+hidden = TRUE
+dependencies[] = action
+dependencies[] = views
diff --git a/core/modules/action/tests/action_bulk_test/action_bulk_test.module b/core/modules/action/tests/action_bulk_test/action_bulk_test.module
new file mode 100644
index 0000000..b3d9bbc
--- /dev/null
+++ b/core/modules/action/tests/action_bulk_test/action_bulk_test.module
@@ -0,0 +1 @@
+<?php
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
new file mode 100644
index 0000000..ea8f701
--- /dev/null
+++ b/core/modules/action/tests/action_bulk_test/config/views.view.test_bulk_form.yml
@@ -0,0 +1,149 @@
+base_table: node
+name: test_bulk_form
+description: ''
+tag: ''
+human_name: form
+core: 8.x
+api_version: '3.0'
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: ''
+    display_options:
+      access:
+        type: perm
+      cache:
+        type: none
+      query:
+        type: views_query
+      exposed_form:
+        type: basic
+      pager:
+        type: full
+        options:
+          items_per_page: '10'
+      style:
+        type: table
+        options:
+          grouping: {  }
+          row_class: ''
+          default_row_class: '1'
+          row_class_special: '1'
+          override: '1'
+          sticky: '0'
+          summary: ''
+          columns:
+            title: title
+            action_bulk_form: action_bulk_form
+          info:
+            title:
+              sortable: '0'
+              default_sort_order: asc
+              align: ''
+              separator: ''
+              empty_column: '0'
+              responsive: ''
+            bulk_form:
+              align: ''
+              separator: ''
+              empty_column: '0'
+              responsive: ''
+          default: '-1'
+          empty_table: '0'
+      row:
+        type: fields
+      fields:
+        title:
+          id: title
+          table: node
+          field: title
+          label: ''
+          alter:
+            alter_text: '0'
+            make_link: '0'
+            absolute: '0'
+            trim: '0'
+            word_boundary: '0'
+            ellipsis: '0'
+            strip_tags: '0'
+            html: '0'
+          hide_empty: '0'
+          empty_zero: '0'
+          link_to_node: '1'
+        bulk_form:
+          id: action_bulk_form
+          table: views
+          field: action_bulk_form
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: 'Bulk form'
+          exclude: '0'
+          alter:
+            alter_text: '0'
+            text: ''
+            make_link: '0'
+            path: ''
+            absolute: '0'
+            external: '0'
+            replace_spaces: '0'
+            path_case: none
+            trim_whitespace: '0'
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: '0'
+            max_length: ''
+            word_boundary: '1'
+            ellipsis: '1'
+            more_link: '0'
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: '0'
+            trim: '0'
+            preserve_tags: ''
+            html: '0'
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: '1'
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: '1'
+          empty: ''
+          hide_empty: '0'
+          empty_zero: '0'
+          hide_alter_empty: '1'
+      filters:
+        status:
+          value: '1'
+          table: node
+          field: status
+          id: status
+          expose:
+            operator: '0'
+          group: '1'
+      sorts:
+        created:
+          id: created
+          table: node
+          field: created
+          order: DESC
+      title: form
+  page_1:
+    display_plugin: page
+    id: page_1
+    display_title: Page
+    position: ''
+    display_options:
+      path: test_bulk_form
+base_field: nid
+disabled: '0'
+module: views
+langcode: und
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 e67614e..7493bf4 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
@@ -814,6 +814,33 @@ public static function getTableJoin($table, $base_table) {
   }
 
   /**
+   * Determines the entity type used by this handler.
+   *
+   * If this handler uses a relationship, the base class of the relationship is
+   * taken into account.
+   *
+   * @return string
+   *   The machine name of the entity type.
+   */
+  public function getEntityType() {
+    // If the user has configured a relationship on the handler take that into
+    // account.
+    if (!empty($this->options['relationship']) && $this->options['relationship'] != 'none') {
+      $views_data = views_fetch_data($this->view->relationship->table);
+    }
+    else {
+      $views_data = views_fetch_data($this->view->storage->get('base_table'));
+    }
+
+    if (isset($views_data['table']['entity type'])) {
+      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->get('name'))));
+    }
+  }
+
+  /**
    * Breaks x,y,z and x+y+z into an array. Numeric only.
    *
    * @param string $str
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 6608d47..1a46513 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -1099,6 +1099,12 @@ function views_hook_info() {
   $hooks['views_data'] = array(
     'group' => 'views',
   );
+  $hooks['views_data_alter'] = array(
+    'group' => 'views',
+  );
+  $hooks['views_form_substitutions'] = array(
+    'group' => 'views',
+  );
 
   return $hooks;
 }
@@ -1627,6 +1633,15 @@ function views_form_views_form($form, &$form_state, ViewExecutable $view, $outpu
     '#weight' => 50,
   );
 
+  $form['actions'] = array(
+    '#type' => 'actions',
+    '#weight' => 100,
+  );
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+
   $substitutions = array();
   foreach ($view->field as $field_name => $field) {
     $form_element_name = $field_name;
@@ -1682,15 +1697,6 @@ function views_form_views_form($form, &$form_state, ViewExecutable $view, $outpu
     '#type' => 'value',
     '#value' => $substitutions,
   );
-  $form['actions'] = array(
-    '#type' => 'container',
-    '#attributes' => array('class' => array('form-actions')),
-    '#weight' => 100,
-  );
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save'),
-  );
 
   return $form;
 }
