diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 9a0d713..ac60a08 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1721,6 +1721,7 @@ function theme_links($variables) {
       }
       // Handle title-only text items.
       else {
+        debug($key);
         // Merge in default array properties into $link.
         $link += array(
           'html' => FALSE,
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php
index b363cc4..2cfb551 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php
@@ -27,40 +27,4 @@ public function load() {
     return $entities;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-    $uri = $entity->uri();
-
-    // Ensure the edit operation exists since it is access controlled.
-    if (isset($operations['edit'])) {
-      // For configuration entities edit path is the MENU_DEFAULT_LOCAL_TASK and
-      // therefore should be accessed by the short route.
-      $operations['edit']['href'] = $uri['path'];
-    }
-
-    if (isset($this->entityInfo['entity_keys']['status'])) {
-      if (!$entity->status()) {
-        $operations['enable'] = array(
-          'title' => t('Enable'),
-          'href' => $uri['path'] . '/enable',
-          'options' => $uri['options'],
-          'weight' => -10,
-        );
-      }
-      else {
-        $operations['disable'] = array(
-          'title' => t('Disable'),
-          'href' => $uri['path'] . '/disable',
-          'options' => $uri['options'],
-          'weight' => 40,
-        );
-      }
-    }
-
-    return $operations;
-  }
-
 }
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityOperationsProvider.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityOperationsProvider.php
new file mode 100644
index 0000000..e3ad4d6
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityOperationsProvider.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Config\Entity\ConfigEntityOperationsProvider.
+ */
+
+namespace Drupal\Core\Config\Entity;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProvider;
+
+/**
+ * Defines a default config entity operations controller.
+ */
+class ConfigEntityOperationsProvider extends EntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $uri = $entity->uri();
+    $operations = parent::getDefaultOperations($entity);
+
+    // For configuration entities edit path is the MENU_DEFAULT_LOCAL_TASK and
+    // therefore should be accessed by the short route.
+    $operations['update']['href'] = $uri['path'];
+
+    $info = $entity->entityInfo();
+    if (isset($info['entity_keys']['status'])) {
+      if (!$entity->status()) {
+        $operations['enable'] = array(
+          'title' => $this->translationManager->translate('Enable'),
+          'href' => $uri['path'] . '/enable',
+          'options' => $uri['options'],
+          'weight' => -10,
+        );
+      }
+      else {
+        $operations['disable'] = array(
+          'title' => $this->translationManager->translate('Disable'),
+          'href' => $uri['path'] . '/disable',
+          'options' => $uri['options'],
+          'weight' => 40,
+        );
+      }
+    }
+
+    return $operations;
+  }
+}
diff --git a/core/lib/Drupal/Core/Config/Entity/DraggableListController.php b/core/lib/Drupal/Core/Config/Entity/DraggableListController.php
index 5370be5..9c4c5bd 100644
--- a/core/lib/Drupal/Core/Config/Entity/DraggableListController.php
+++ b/core/lib/Drupal/Core/Config/Entity/DraggableListController.php
@@ -8,9 +8,11 @@
 namespace Drupal\Core\Config\Entity;
 
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProviderInterface;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Session\AccountInterface;
 
 /**
  * Provides a list controller for draggable configuration entities.
@@ -41,8 +43,8 @@
   /**
    * {@inheritdoc}
    */
-  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler) {
-    parent::__construct($entity_type, $entity_info, $storage, $module_handler);
+  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, EntityOperationsProviderInterface $operations, ModuleHandlerInterface $module_handler, AccountInterface $current_user) {
+    parent::__construct($entity_type, $entity_info, $storage, $operations, $module_handler, $current_user);
 
     // Check if the entity type supports weighting.
     if (!empty($this->entityInfo['entity_keys']['weight'])) {
diff --git a/core/lib/Drupal/Core/Entity/Annotation/EntityType.php b/core/lib/Drupal/Core/Entity/Annotation/EntityType.php
index b46d9f7..1b55f0c 100644
--- a/core/lib/Drupal/Core/Entity/Annotation/EntityType.php
+++ b/core/lib/Drupal/Core/Entity/Annotation/EntityType.php
@@ -57,6 +57,10 @@ class EntityType extends Plugin {
    * - translation: The name of the controller class that should be used to
    *   handle the translation process. The class must implement
    *   \Drupal\content_translation\ContentTranslationControllerInterface.
+   * - operations: The name of the controller class that provides entity
+   *   operations, for which access checks must be run through the "access"
+   *   controller. The class must implement
+   *   \Drupal\Core\Entity\EntityOperationsProviderInterface.
    *
    * @todo Interfaces from outside \Drupal\Core or \Drupal\Component should not
    *   be used here.
diff --git a/core/lib/Drupal/Core/Entity/EntityListController.php b/core/lib/Drupal/Core/Entity/EntityListController.php
index 0a722a0..8bd2ccb 100644
--- a/core/lib/Drupal/Core/Entity/EntityListController.php
+++ b/core/lib/Drupal/Core/Entity/EntityListController.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Component\Utility\String;
@@ -18,6 +19,13 @@
 class EntityListController implements EntityListControllerInterface, EntityControllerInterface {
 
   /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $currentUser;
+
+  /**
    * The entity storage controller class.
    *
    * @var \Drupal\Core\Entity\EntityStorageControllerInterface
@@ -25,6 +33,13 @@ class EntityListController implements EntityListControllerInterface, EntityContr
   protected $storage;
 
   /**
+   * The entity operations controller.
+   *
+   * @var \Drupal\Core\Entity\EntityOperationsProviderInterface
+   */
+  protected $operations;
+
+  /**
    * The module handler to invoke hooks on.
    *
    * @var \Drupal\Core\Extension\ModuleHandlerInterface
@@ -62,7 +77,9 @@ public static function createInstance(ContainerInterface $container, $entity_typ
       $entity_type,
       $entity_info,
       $container->get('entity.manager')->getStorageController($entity_type),
-      $container->get('module_handler')
+      $container->get('entity.manager')->getOperationsProvider($entity_type),
+      $container->get('module_handler'),
+      $container->get('current_user')
     );
   }
 
@@ -75,14 +92,20 @@ public static function createInstance(ContainerInterface $container, $entity_typ
    *   An array of entity info for the entity type.
    * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage
    *   The entity storage controller class.
+   * @param \Drupal\Core\Entity\EntityOperationsProviderInterface $operations
+   *   The entity operations controller.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke hooks on.
+   * @param \Drupal\Core\Session\AccountInterface $current_user
+   *   The current user.
    */
-  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler) {
+  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, EntityOperationsProviderInterface $operations, ModuleHandlerInterface $module_handler, AccountInterface $current_user) {
     $this->entityType = $entity_type;
     $this->storage = $storage;
+    $this->operations = $operations;
     $this->entityInfo = $entity_info;
     $this->moduleHandler = $module_handler;
+    $this->currentUser = $current_user;
   }
 
   /**
@@ -113,33 +136,6 @@ protected function getLabel(EntityInterface $entity) {
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function getOperations(EntityInterface $entity) {
-    $uri = $entity->uri();
-
-    $operations = array();
-    if ($entity->access('update')) {
-      $operations['edit'] = array(
-        'title' => $this->t('Edit'),
-        'href' => $uri['path'] . '/edit',
-        'options' => $uri['options'],
-        'weight' => 10,
-      );
-    }
-    if ($entity->access('delete')) {
-      $operations['delete'] = array(
-        'title' => $this->t('Delete'),
-        'href' => $uri['path'] . '/delete',
-        'options' => $uri['options'],
-        'weight' => 100,
-      );
-    }
-
-    return $operations;
-  }
-
-  /**
    * Builds the header row for the entity listing.
    *
    * @return array
@@ -164,31 +160,12 @@ public function buildHeader() {
    * @see \Drupal\Core\Entity\EntityListController::render()
    */
   public function buildRow(EntityInterface $entity) {
-    $row['operations']['data'] = $this->buildOperations($entity);
-    return $row;
-  }
-
-  /**
-   * Builds a renderable list of operation links for the entity.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity on which the linked operations will be performed.
-   *
-   * @return array
-   *   A renderable array of operation links.
-   *
-   * @see \Drupal\Core\Entity\EntityListController::render()
-   */
-  public function buildOperations(EntityInterface $entity) {
-    // Retrieve and sort operations.
-    $operations = $this->getOperations($entity);
-    $this->moduleHandler->alter('entity_operation', $operations, $entity);
-    uasort($operations, 'drupal_sort_weight');
-    $build = array(
+    $row['operations']['data'] = array(
       '#type' => 'operations',
-      '#links' => $operations,
+      '#links' => $this->operations->getOperations($entity, $this->currentUser),
     );
-    return $build;
+
+    return $row;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/EntityListControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityListControllerInterface.php
index b7581d8..a56d959 100644
--- a/core/lib/Drupal/Core/Entity/EntityListControllerInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityListControllerInterface.php
@@ -32,22 +32,6 @@ public function getStorageController();
   public function load();
 
   /**
-   * Provides an array of information to build a list of operation links.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity the operations are for.
-   *
-   * @return array
-   *   An associative array of operation link data for this list, keyed by
-   *   operation name, containing the following key-value pairs:
-   *   - title: The localized title of the operation.
-   *   - href: The path for the operation.
-   *   - options: An array of URL options for the path.
-   *   - weight: The weight of this operation.
-   */
-  public function getOperations(EntityInterface $entity);
-
-  /**
    * Renders the list page markup to be output.
    *
    * @return string
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 5fc2d16..f1e9fd5 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -286,6 +286,18 @@ protected function getController($entity_type, $controller_type) {
   }
 
   /**
+   * Gets an entity type's operations controller.
+   *
+   * @param string $entity_type
+   *   The entity type for this operations controller.
+   *
+   * @return \Drupal\Core\Entity\EntityOperationsProviderInterface.
+   */
+  public function getOperationsProvider($entity_type) {
+    return $this->getController($entity_type, 'operations');
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function getForm(EntityInterface $entity, $operation = 'default', array $form_state = array()) {
diff --git a/core/lib/Drupal/Core/Entity/EntityOperationsProvider.php b/core/lib/Drupal/Core/Entity/EntityOperationsProvider.php
new file mode 100644
index 0000000..4b1c148
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/EntityOperationsProvider.php
@@ -0,0 +1,104 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\EntityOperationsProvider.
+ */
+
+namespace Drupal\Core\Entity;
+
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\StringTranslation\TranslationManager;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Defines a default entity operations controller.
+ */
+class EntityOperationsProvider implements EntityOperationsProviderInterface, EntityControllerInterface {
+
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * The translation manager.
+   *
+   * @var \Drupal\Core\StringTranslation\TranslationManager
+   */
+  protected $translationManager;
+
+  /**
+   * Constructs an EntityOperationsProvider object.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   * @param \Drupal\Core\StringTranslation\TranslationManager $translation_manager
+   * @param \Drupal\Core\Entity\EntityAccessControllerInterface $access_controller
+   */
+  public function __construct(ModuleHandlerInterface $module_handler, TranslationManager $translation_manager) {
+    $this->moduleHandler = $module_handler;
+    $this->translationManager = $translation_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+    return new static($container->get('module_handler'), $container->get('string_translation'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getOperations(EntityInterface $entity, AccountInterface $account) {
+    // Operations are retrieved from specific to non-specific contexts (the
+    // controller, the entity-type-specific hook, and the generic hook).
+    $operations = $this->getDefaultOperations($entity);
+    $hooks = array($entity->entityType() . '_operations' , 'entity_operations');
+    foreach ($hooks as $hook) {
+      $operations = array_merge($this->moduleHandler->invokeAll($hook, array($entity)), $operations);
+    }
+    $this->moduleHandler->alter(array('entity_operations', $entity->entityType() . '_operations'), $entity, $operations);
+
+    // Check access to the operations.
+    foreach ($operations as $operation => $operation_link) {
+      if (!$entity->access($operation, $account)) {
+        unset($operations[$operation]);
+      }
+    }
+// @todo Sort operations by weight and human-readable label.
+
+    return $operations;
+  }
+
+  /**
+   * Gets the entity's default operations.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *
+   * @return array
+   *   The structure is identical to that of the return value of
+   *   self::getOperations().
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $uri = $entity->uri();
+    $operations = array();
+    $operations['update'] = array(
+      'title' => $this->translationManager->translate('Edit'),
+      'href' => $uri['path'] . '/edit',
+      'options' => $uri['options'],
+      'weight' => 10,
+    );
+    $operations['delete'] = array(
+      'title' => $this->translationManager->translate('Delete'),
+      'href' => $uri['path'] . '/delete',
+      'options' => $uri['options'],
+      'weight' => 100,
+    );
+
+    return $operations;
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/EntityOperationsProviderInterface.php b/core/lib/Drupal/Core/Entity/EntityOperationsProviderInterface.php
new file mode 100644
index 0000000..f0a3dbf
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/EntityOperationsProviderInterface.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\EntityOperationsProviderInterface.
+ */
+
+namespace Drupal\Core\Entity;
+
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Defines an interface to retrieve all operations of an entity.
+ *
+ * Operations controllers must return all known operations. Access control must
+ * be done through entities' "access" controllers.
+ */
+interface EntityOperationsProviderInterface {
+
+  /**
+   * Gets all operations for an entity that are accessible by a user account.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *
+   * @return array
+   *   An array of operations.
+   * @todo Document array structure.
+   */
+  public function getOperations(EntityInterface $entity, AccountInterface $account);
+
+}
diff --git a/core/modules/action/lib/Drupal/action/ActionListController.php b/core/modules/action/lib/Drupal/action/ActionListController.php
index 405f224..dd999e2 100644
--- a/core/modules/action/lib/Drupal/action/ActionListController.php
+++ b/core/modules/action/lib/Drupal/action/ActionListController.php
@@ -11,8 +11,10 @@
 use Drupal\Core\Entity\EntityControllerInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Config\Entity\ConfigEntityListController;
+use Drupal\Core\Entity\EntityOperationsProviderInterface;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -41,13 +43,17 @@ class ActionListController extends ConfigEntityListController implements EntityC
    *   An array of entity info for the entity type.
    * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage
    *   The action storage controller.
+   * @param \Drupal\Core\Entity\EntityOperationsProviderInterface $operations
+   *   The entity operations provider.
    * @param \Drupal\Core\Action\ActionManager $action_manager
    *   The action plugin manager.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke hooks on.
+   * @param |Drupal\Core\Session\AccountInterface $current_user
+   *   The current user.
    */
-  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ActionManager $action_manager, ModuleHandlerInterface $module_handler) {
-    parent::__construct($entity_type, $entity_info, $storage, $module_handler);
+  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, EntityOperationsProviderInterface $operations, ActionManager $action_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user) {
+    parent::__construct($entity_type, $entity_info, $storage, $operations, $module_handler, $current_user);
 
     $this->actionManager = $action_manager;
   }
@@ -60,8 +66,10 @@ public static function createInstance(ContainerInterface $container, $entity_typ
       $entity_type,
       $entity_info,
       $container->get('entity.manager')->getStorageController($entity_type),
+      $container->get('entity.manager')->getOperationsProvider($entity_type),
       $container->get('plugin.manager.action'),
-      $container->get('module_handler')
+      $container->get('module_handler'),
+      $container->get('current_user')
     );
   }
 
@@ -105,17 +113,6 @@ public function buildHeader() {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = $entity->isConfigurable() ? parent::getOperations($entity) : array();
-    if (isset($operations['edit'])) {
-      $operations['edit']['title'] = t('Configure');
-    }
-    return $operations;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function render() {
     $build['action_header']['#markup'] = '<h3>' . t('Available actions:') . '</h3>';
     $build['action_table'] = parent::render();
diff --git a/core/modules/action/lib/Drupal/action/ActionOperationsProvider.php b/core/modules/action/lib/Drupal/action/ActionOperationsProvider.php
new file mode 100644
index 0000000..1e476c2
--- /dev/null
+++ b/core/modules/action/lib/Drupal/action/ActionOperationsProvider.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\action\ActionOperationsProvider.
+ */
+
+namespace Drupal\action;
+
+use Drupal\Core\Config\Entity\ConfigEntityOperationsProvider;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Defines a entity operations controller for action entities.
+ */
+class ActionOperationsProvider extends ConfigEntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    if (!$entity->isConfigurable()) {
+      return array();
+    }
+
+    $operations = parent::getDefaultOperations($entity);
+    $operations['update']['title'] = t('Configure');
+    return $operations;
+  }
+}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListController.php
index efa31b3..012e2b8 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListController.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListController.php
@@ -31,18 +31,4 @@ public function buildRow(EntityInterface $entity) {
     return $row + parent::buildRow($entity);
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-    // The custom block edit path does not contain '/edit'.
-    if (isset($operations['edit'])) {
-      $uri = $entity->uri();
-      $operations['edit']['href'] = $uri['path'];
-      $operations['edit']['query']['destination'] = 'admin/structure/block/custom-blocks';
-    }
-    return $operations;
-  }
-
 }
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockOperationsProvider.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockOperationsProvider.php
new file mode 100644
index 0000000..974cda3
--- /dev/null
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockOperationsProvider.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\custom_block\CustomBlockOperationsProvider.
+ */
+
+namespace Drupal\custom_block;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProvider;
+
+/**
+ * Provides an operations controller for custom_block entities.
+ */
+class CustomBlockOperationsProvider extends EntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    // The custom block edit path does not contain '/edit'.
+    $uri = $entity->uri();
+    $operations['update']['href'] = $uri['path'];
+    $operations['update']['query']['destination'] = 'admin/structure/block/custom-blocks';
+
+    return $operations;
+  }
+
+}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php
index efa4380..004b1af 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php
@@ -16,19 +16,6 @@
 class CustomBlockTypeListController extends ConfigEntityListController {
 
   /**
-   * {@inheritdoc}
-   */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-    // Place the edit operation after the operations added by field_ui.module
-    // which have the weights 15, 20, 25.
-    if (isset($operations['edit'])) {
-      $operations['edit']['weight'] = 30;
-    }
-    return $operations;
-  }
-
-  /**
    * Overrides \Drupal\Core\Entity\EntityListController::buildHeader().
    */
   public function buildHeader() {
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeOperationsProvider.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeOperationsProvider.php
new file mode 100644
index 0000000..3793f97
--- /dev/null
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeOperationsProvider.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\custom_block\CustomBlockTypeOperationsProvider.
+ */
+
+namespace Drupal\custom_block;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProvider;
+
+/**
+ * Defines a entity operations controller for custom_block entities.
+ */
+class CustomBlockTypeOperationsProvider extends EntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    // Place the edit operation after the operations added by field_ui.module
+    // which have the weights 15, 20, 25.
+    $operations['update']['weight'] = 30;
+
+    return $operations;
+  }
+}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php
index 2baf1fe..7b5aecc 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php
@@ -21,6 +21,7 @@
  *   label = @Translation("Custom Block"),
  *   bundle_label = @Translation("Custom Block type"),
  *   controllers = {
+ *     "operations" = "Drupal\custom_block\CustomBlockOperationsProvider",
  *     "storage" = "Drupal\custom_block\CustomBlockStorageController",
  *     "access" = "Drupal\custom_block\CustomBlockAccessController",
  *     "list" = "Drupal\custom_block\CustomBlockListController",
diff --git a/core/modules/block/lib/Drupal/block/BlockListController.php b/core/modules/block/lib/Drupal/block/BlockListController.php
index 874ff35..0a22154 100644
--- a/core/modules/block/lib/Drupal/block/BlockListController.php
+++ b/core/modules/block/lib/Drupal/block/BlockListController.php
@@ -13,9 +13,11 @@
 use Drupal\Core\Config\Entity\ConfigEntityListController;
 use Drupal\Core\Entity\EntityControllerInterface;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProviderInterface;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -60,14 +62,18 @@ class BlockListController extends ConfigEntityListController implements FormInte
    * @param array $entity_info
    *   An array of entity info for the entity type.
    * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage
+   * @param \Drupal\Core\Entity\EntityOperationsProviderInterface $operations
+   *   The entity operations provider.
    *   The entity storage controller class.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke hooks on.
+   * @param |Drupal\Core\Session\AccountInterface $current_user
+   *   The current user.
    * @param \Drupal\Component\Plugin\PluginManagerInterface $block_manager
    *   The block manager.
    */
-  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler, PluginManagerInterface $block_manager) {
-    parent::__construct($entity_type, $entity_info, $storage, $module_handler);
+  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, EntityOperationsProviderInterface $operations, ModuleHandlerInterface $module_handler, AccountInterface $current_user, PluginManagerInterface $block_manager) {
+    parent::__construct($entity_type, $entity_info, $storage, $operations, $module_handler, $current_user);
 
     $this->blockManager = $block_manager;
   }
@@ -80,7 +86,9 @@ public static function createInstance(ContainerInterface $container, $entity_typ
       $entity_type,
       $entity_info,
       $container->get('entity.manager')->getStorageController($entity_type),
+      $container->get('entity.manager')->getOperationsProvider($entity_type),
       $container->get('module_handler'),
+      $container->get('current_user'),
       $container->get('plugin.manager.block')
     );
   }
@@ -287,7 +295,10 @@ public function buildForm(array $form, array &$form_state) {
               'class' => array('block-weight', 'block-weight-' . $region),
             ),
           );
-          $form['blocks'][$entity_id]['operations'] = $this->buildOperations($info['entity']);
+          $form['blocks'][$entity_id]['operations']['data'] = array(
+            '#type' => 'operations',
+            '#links' => $this->operations->getOperations($info['entity'], $this->currentUser),
+          );
         }
       }
     }
@@ -375,19 +386,6 @@ public function buildForm(array $form, array &$form_state) {
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-
-    if (isset($operations['edit'])) {
-      $operations['edit']['title'] = t('Configure');
-    }
-
-    return $operations;
-  }
-
-  /**
    * Implements \Drupal\Core\Form\FormInterface::validateForm().
    */
   public function validateForm(array &$form, array &$form_state) {
diff --git a/core/modules/block/lib/Drupal/block/Entity/Block.php b/core/modules/block/lib/Drupal/block/Entity/Block.php
index f433ea6..608fc85 100644
--- a/core/modules/block/lib/Drupal/block/Entity/Block.php
+++ b/core/modules/block/lib/Drupal/block/Entity/Block.php
@@ -21,6 +21,7 @@
  *   id = "block",
  *   label = @Translation("Block"),
  *   controllers = {
+ *     "operations" = "Drupal\Core\Config\Entity\ConfigEntityOperationsProvider",
  *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
  *     "access" = "Drupal\block\BlockAccessController",
  *     "view_builder" = "Drupal\block\BlockViewBuilder",
diff --git a/core/modules/block/lib/Drupal/block/Entity/BlockOperationsProvider.php b/core/modules/block/lib/Drupal/block/Entity/BlockOperationsProvider.php
new file mode 100644
index 0000000..7632b4a
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/Entity/BlockOperationsProvider.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block\BlockOperationsProvider.
+ */
+
+namespace Drupal\block;
+
+use Drupal\Core\Config\Entity\ConfigEntityOperationsProvider;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Defines a entity operations controller for block entities.
+ */
+class BlockOperationsProvider extends ConfigEntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    $operations['update']['title'] = t('Configure');
+
+    return $operations;
+  }
+}
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php
index b26e7f2..d286c7d 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListTest.php
@@ -50,34 +50,6 @@ function testList() {
     $this->assertTrue(!empty($entity), '"Default" ConfigTest entity ID found.');
     $this->assertTrue($entity instanceof ConfigTest, '"Default" ConfigTest entity is an instance of ConfigTest.');
 
-    // Test getOperations() method.
-    $uri = $entity->uri();
-    $expected_operations = array(
-      'edit' => array (
-        'title' => t('Edit'),
-        'href' => $uri['path'],
-        'options' => $uri['options'],
-        'weight' => 10,
-      ),
-      'disable' => array(
-        'title' => t('Disable'),
-        'href' => $uri['path'] . '/disable',
-        'options' => $uri['options'],
-        'weight' => 40,
-      ),
-      'delete' => array (
-        'title' => t('Delete'),
-        'href' => $uri['path'] . '/delete',
-        'options' => $uri['options'],
-        'weight' => 100,
-      ),
-    );
-
-    $actual_operations = $controller->getOperations($entity);
-    // Sort the operations to normalize link order.
-    uasort($actual_operations, 'drupal_sort_weight');
-    $this->assertIdentical($expected_operations, $actual_operations);
-
     // Test buildHeader() method.
     $expected_items = array(
       'label' => 'Label',
@@ -88,15 +60,12 @@ function testList() {
     $this->assertIdentical($expected_items, $actual_items, 'Return value from buildHeader matches expected.');
 
     // Test buildRow() method.
-    $build_operations = $controller->buildOperations($entity);
     $expected_items = array(
       'label' => 'Default',
       'id' => 'dotted.default',
-      'operations' => array(
-        'data' => $build_operations,
-      ),
     );
     $actual_items = $controller->buildRow($entity);
+    unset($actual_items['operations']);
     $this->assertIdentical($expected_items, $actual_items, 'Return value from buildRow matches expected.');
     // Test sorting.
     $storage_controller = $controller->getStorageController();
@@ -120,36 +89,6 @@ function testList() {
     $entity->save();
     $list = $controller->load();
     $this->assertIdentical(array_keys($list), array('beta', 'dotted.default', 'alpha', 'omega'));
-
-    // Test that config entities that do not support status, do not have
-    // enable/disable operations.
-    $controller = $this->container->get('entity.manager')
-      ->getListController('config_test_no_status');
-
-    $list = $controller->load();
-    $entity = $list['default'];
-
-    // Test getOperations() method.
-    $uri = $entity->uri();
-    $expected_operations = array(
-      'edit' => array(
-        'title' => t('Edit'),
-        'href' => $uri['path'],
-        'options' => $uri['options'],
-        'weight' => 10,
-      ),
-      'delete' => array(
-        'title' => t('Delete'),
-        'href' => $uri['path'] . '/delete',
-        'options' => $uri['options'],
-        'weight' => 100,
-      ),
-    );
-
-    $actual_operations = $controller->getOperations($entity);
-    // Sort the operations to normalize link order.
-    uasort($actual_operations, 'drupal_sort_weight');
-    $this->assertIdentical($expected_operations, $actual_operations);
   }
 
   /**
diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigTest.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigTest.php
index 19ee07f..b207572 100644
--- a/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigTest.php
+++ b/core/modules/config/tests/config_test/lib/Drupal/config_test/Entity/ConfigTest.php
@@ -19,6 +19,7 @@
  *   id = "config_test",
  *   label = @Translation("Test configuration"),
  *   controllers = {
+ *     "operations" = "Drupal\Core\Config\Entity\ConfigEntityOperationsProvider",
  *     "storage" = "Drupal\config_test\ConfigTestStorageController",
  *     "list" = "Drupal\config_test\ConfigTestListController",
  *     "form" = {
diff --git a/core/modules/contact/lib/Drupal/contact/Entity/Category.php b/core/modules/contact/lib/Drupal/contact/Entity/Category.php
index e636713..b369906 100644
--- a/core/modules/contact/lib/Drupal/contact/Entity/Category.php
+++ b/core/modules/contact/lib/Drupal/contact/Entity/Category.php
@@ -20,6 +20,7 @@
  *   id = "contact_category",
  *   label = @Translation("Contact category"),
  *   controllers = {
+ *     "operations" = "Drupal\Core\Config\Entity\ConfigEntityOperationsProvider",
  *     "storage" = "Drupal\contact\CategoryStorageController",
  *     "access" = "Drupal\contact\CategoryAccessController",
  *     "list" = "Drupal\contact\CategoryListController",
diff --git a/core/modules/entity/lib/Drupal/entity/Entity/EntityFormMode.php b/core/modules/entity/lib/Drupal/entity/Entity/EntityFormMode.php
index 533321c..def662c 100644
--- a/core/modules/entity/lib/Drupal/entity/Entity/EntityFormMode.php
+++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityFormMode.php
@@ -33,6 +33,7 @@
  *   id = "form_mode",
  *   label = @Translation("Form mode"),
  *   controllers = {
+ *     "operations" = "Drupal\Core\Config\Entity\ConfigEntityOperationsProvider",
  *     "list" = "Drupal\entity\EntityFormModeListController",
  *     "form" = {
  *       "add" = "Drupal\entity\Form\EntityFormModeAddForm",
diff --git a/core/modules/entity/lib/Drupal/entity/Entity/EntityViewMode.php b/core/modules/entity/lib/Drupal/entity/Entity/EntityViewMode.php
index 6107d4f..6b04148 100644
--- a/core/modules/entity/lib/Drupal/entity/Entity/EntityViewMode.php
+++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityViewMode.php
@@ -34,6 +34,7 @@
  *   id = "view_mode",
  *   label = @Translation("View mode"),
  *   controllers = {
+ *     "operations" = "Drupal\Core\Config\Entity\ConfigEntityOperationsProvider",
  *     "list" = "Drupal\entity\EntityDisplayModeListController",
  *     "form" = {
  *       "add" = "Drupal\entity\Form\EntityDisplayModeAddForm",
diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayModeListController.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayModeListController.php
index 835c1c6..81227c8 100644
--- a/core/modules/entity/lib/Drupal/entity/EntityDisplayModeListController.php
+++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayModeListController.php
@@ -9,8 +9,10 @@
 
 use Drupal\Core\Config\Entity\ConfigEntityListController;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProviderInterface;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -34,13 +36,17 @@ class EntityDisplayModeListController extends ConfigEntityListController {
    *   An array of entity info for the entity type.
    * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage
    *   The entity storage controller class.
+   * @param \Drupal\Core\Entity\EntityOperationsProviderInterface $operations
+   *   The entity operations provider.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke hooks on.
+   * @param |Drupal\Core\Session\AccountInterface $current_user
+   *   The current user.
    * @param array $entity_info_complete
    *   The entity info for all entity types.
    */
-  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler, array $entity_info_complete) {
-    parent::__construct($entity_type, $entity_info, $storage, $module_handler);
+  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, EntityOperationsProviderInterface $operations, ModuleHandlerInterface $module_handler, AccountInterface $current_user, array $entity_info_complete) {
+    parent::__construct($entity_type, $entity_info, $storage, $operations, $module_handler, $current_user);
 
     $this->entityInfoComplete = $entity_info_complete;
   }
@@ -54,7 +60,9 @@ public static function createInstance(ContainerInterface $container, $entity_typ
       $entity_type,
       $entity_info,
       $entity_manager->getStorageController($entity_type),
+      $entity_manager->getOperationsProvider($entity_type),
       $container->get('module_handler'),
+      $container->get('current_user'),
       $entity_manager->getDefinitions()
     );
   }
diff --git a/core/modules/field/lib/Drupal/field/Entity/Field.php b/core/modules/field/lib/Drupal/field/Entity/Field.php
index 47003fb..ad194d6 100644
--- a/core/modules/field/lib/Drupal/field/Entity/Field.php
+++ b/core/modules/field/lib/Drupal/field/Entity/Field.php
@@ -23,6 +23,7 @@
  *   id = "field_entity",
  *   label = @Translation("Field"),
  *   controllers = {
+ *     "operations" = "Drupal\Core\Config\Entity\ConfigEntityOperationsProvider",
  *     "storage" = "Drupal\field\FieldStorageController"
  *   },
  *   config_prefix = "field.field",
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index dc0d38f..361f680 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -179,6 +179,64 @@ function field_ui_permission() {
 }
 
 /**
+ * Implements hook_entity_operations().
+ */
+function field_ui_entity_operations(EntityInterface $entity) {
+  $info = $entity->entityInfo();
+  $operations = array();
+
+  // If the entity is fieldable, or if it is the bundle of a fieldable entity
+  // type, add field administration links.
+  if ($info['fieldable'] || !empty($info['bundle_of'])) {
+    $uri = $entity->uri();
+    $operations['manage-fields'] = array(
+      'title' => t('Manage fields'),
+      'href' => $uri['path'] . '/fields',
+      'options' => $uri['options'],
+      'weight' => 15,
+    );
+    $operations['manage-display'] = array(
+      'title' => t('Manage display'),
+      'href' => $uri['path'] . '/display',
+      'options' => $uri['options'],
+      'weight' => 25,
+    );
+  }
+
+  // If the entity is the bundle of a fieldable entity type, add additional
+  // field administration links.
+  if (!empty($info['bundle_of'])) {
+    $uri = $entity->uri();
+    $operations['manage-form-display'] = array(
+      'title' => t('Manage form display'),
+      'href' => $uri['path'] . '/form-display',
+      'options' => $uri['options'],
+      'weight' => 20,
+    );
+  }
+
+  return $operations;
+}
+
+/**
+ * Implements hook_entity_access().
+ */
+function field_ui_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) {
+  $info = $entity->entityInfo();
+  $entity_type = isset($info['bundle_of']) ? $info['bundle_of'] : $entity->entityType();
+
+  if ($operation == 'manage-fields') {
+    return $account->hasPermission('administer ' . $entity_type . ' fields');
+  }
+  if ($operation == 'manage-form-display') {
+    return $account->hasPermission('administer ' . $entity_type . ' form display');
+  }
+  if ($operation == 'manage-display') {
+    return $account->hasPermission('administer ' . $entity_type . ' display');
+  }
+}
+
+/**
  * Menu loader callback: Loads a field instance based on field and bundle name.
  *
  * @param $field_name
@@ -291,43 +349,6 @@ function field_ui_form_node_type_form_alter(&$form, $form_state) {
 }
 
 /**
- * Implements hook_entity_operation_alter().
- */
-function field_ui_entity_operation_alter(array &$operations, EntityInterface $entity) {
-  $info = $entity->entityInfo();
-  // Add manage fields and display links if this entity type is the bundle
-  // of another.
-  if (!empty($info['bundle_of'])) {
-    $bundle_of = $info['bundle_of'];
-    $uri = $entity->uri();
-    if (user_access('administer '. $bundle_of . ' fields')) {
-      $operations['manage-fields'] = array(
-        'title' => t('Manage fields'),
-        'href' => $uri['path'] . '/fields',
-        'options' => $uri['options'],
-        'weight' => 15,
-      );
-    }
-    if (user_access('administer '. $bundle_of . ' form display')) {
-      $operations['manage-form-display'] = array(
-        'title' => t('Manage form display'),
-        'href' => $uri['path'] . '/form-display',
-        'options' => $uri['options'],
-        'weight' => 20,
-      );
-    }
-    if (user_access('administer '. $bundle_of . ' display')) {
-      $operations['manage-display'] = array(
-        'title' => t('Manage display'),
-        'href' => $uri['path'] . '/display',
-        'options' => $uri['options'],
-        'weight' => 25,
-      );
-    }
-  }
-}
-
-/**
  * Form submission handler for the 'Save and manage fields' button.
  *
  * @see field_ui_form_node_type_form_alter()
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldListController.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldListController.php
index 0025379..5ea2ac5 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/FieldListController.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldListController.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Field\FieldTypePluginManager;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -58,13 +59,15 @@ class FieldListController extends ConfigEntityListController {
    *   The entity manager.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke hooks on.
+   * @param |Drupal\Core\Session\AccountInterface $current_user
+   *   The current user.
    * @param \Drupal\field\FieldInfo $field_info
    *   The field info service.
    * @param \Drupal\Core\Field\FieldTypePluginManager $field_type_manager
    *   The 'field type' plugin manager.
    */
-  public function __construct($entity_type, array $entity_info, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, FieldTypePluginManager $field_type_manager) {
-    parent::__construct($entity_type, $entity_info, $entity_manager->getStorageController($entity_type), $module_handler);
+  public function __construct($entity_type, array $entity_info, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user, FieldTypePluginManager $field_type_manager) {
+    parent::__construct($entity_type, $entity_info, $entity_manager->getStorageController($entity_type), $entity_manager->getOperationsProvider($entity_type), $module_handler, $current_user);
 
     $this->entityManager = $entity_manager;
     $this->bundles = entity_get_bundles();
@@ -81,6 +84,7 @@ public static function createInstance(ContainerInterface $container, $entity_typ
       $entity_info,
       $container->get('entity.manager'),
       $container->get('module_handler'),
+      $container->get('current_user'),
       $container->get('plugin.manager.field.field_type')
     );
   }
diff --git a/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php b/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php
index 6c4bf5b..a9823e6 100644
--- a/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php
+++ b/core/modules/filter/lib/Drupal/filter/Entity/FilterFormat.php
@@ -21,6 +21,7 @@
  *   id = "filter_format",
  *   label = @Translation("Text format"),
  *   controllers = {
+ *     "operations" = "Drupal\filter\FilterFormatOperationsProvider",
  *     "form" = {
  *       "add" = "Drupal\filter\FilterFormatAddFormController",
  *       "edit" = "Drupal\filter\FilterFormatEditFormController",
diff --git a/core/modules/filter/lib/Drupal/filter/FilterFormatAccessController.php b/core/modules/filter/lib/Drupal/filter/FilterFormatAccessController.php
index a1edbd9..2d30711 100644
--- a/core/modules/filter/lib/Drupal/filter/FilterFormatAccessController.php
+++ b/core/modules/filter/lib/Drupal/filter/FilterFormatAccessController.php
@@ -30,6 +30,10 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
     if ($operation == 'delete') {
       return FALSE;
     }
+    // The fallback format may not be disabled.
+    if ($operation == 'disable' && $entity->isFallbackFormat()) {
+      return FALSE;
+    }
 
     if ($operation != 'view' && $account->hasPermission('administer filters')) {
       return TRUE;
diff --git a/core/modules/filter/lib/Drupal/filter/FilterFormatListController.php b/core/modules/filter/lib/Drupal/filter/FilterFormatListController.php
index cd94f86..ca980c5 100644
--- a/core/modules/filter/lib/Drupal/filter/FilterFormatListController.php
+++ b/core/modules/filter/lib/Drupal/filter/FilterFormatListController.php
@@ -12,8 +12,10 @@
 use Drupal\Core\Config\Entity\DraggableListController;
 use Drupal\Core\Entity\EntityControllerInterface;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProviderInterface;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -42,13 +44,17 @@ class FilterFormatListController extends DraggableListController implements Enti
    *   An array of entity info for the entity type.
    * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage
    *   The entity storage controller class.
+   * @param \Drupal\Core\Entity\EntityOperationsProviderInterface $operations
+   *   The entity operations provider.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke hooks on.
+   * @param |Drupal\Core\Session\AccountInterface $current_user
+   *   The current user.
    * @param \Drupal\Core\Config\ConfigFactory $config_factory
    *   The config factory.
    */
-  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler, ConfigFactory $config_factory) {
-    parent::__construct($entity_type, $entity_info, $storage, $module_handler);
+  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, EntityOperationsProviderInterface $operations, ModuleHandlerInterface $module_handler, AccountInterface $current_user, ConfigFactory $config_factory) {
+    parent::__construct($entity_type, $entity_info, $storage, $operations, $module_handler, $current_user);
 
     $this->configFactory = $config_factory;
   }
@@ -61,7 +67,9 @@ public static function createInstance(ContainerInterface $container, $entity_typ
       $entity_type,
       $entity_info,
       $container->get('entity.manager')->getStorageController($entity_type),
+      $container->get('entity.manager')->getOperationsProvider($entity_type),
       $container->get('module_handler'),
+      $container->get('current_user'),
       $container->get('config.factory')
     );
   }
@@ -123,24 +131,6 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-
-    if (isset($operations['edit'])) {
-      $operations['edit']['title'] = t('Configure');
-    }
-
-    // The fallback format may not be disabled.
-    if ($entity->isFallbackFormat()) {
-      unset($operations['disable']);
-    }
-
-    return $operations;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function buildForm(array $form, array &$form_state) {
     $form = parent::buildForm($form, $form_state);
     $form['actions']['submit']['#value'] = t('Save changes');
diff --git a/core/modules/filter/lib/Drupal/filter/FilterFormatOperationsProvider.php b/core/modules/filter/lib/Drupal/filter/FilterFormatOperationsProvider.php
new file mode 100644
index 0000000..208b9fc
--- /dev/null
+++ b/core/modules/filter/lib/Drupal/filter/FilterFormatOperationsProvider.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\filter\FilterFormatOperationsProvider.
+ */
+
+namespace Drupal\filter;
+
+use Drupal\Core\Config\Entity\ConfigEntityOperationsProvider;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Defines a entity operations controller for filter_format entities.
+ */
+class FilterFormatOperationsProvider extends ConfigEntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    $operations['update']['title'] = t('Configure');
+
+    return $operations;
+  }
+}
diff --git a/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php b/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php
index a8d0e21..0c8621f 100644
--- a/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php
+++ b/core/modules/image/lib/Drupal/image/Entity/ImageStyle.php
@@ -25,6 +25,7 @@
  *   id = "image_style",
  *   label = @Translation("Image style"),
  *   controllers = {
+ *     "operations" = "Drupal\Core\Config\Entity\ConfigEntityOperationsProvider",
  *     "form" = {
  *       "add" = "Drupal\image\Form\ImageStyleAddForm",
  *       "edit" = "Drupal\image\Form\ImageStyleEditForm",
diff --git a/core/modules/image/lib/Drupal/image/ImageStyleListController.php b/core/modules/image/lib/Drupal/image/ImageStyleListController.php
index 984fe89..54997f7 100644
--- a/core/modules/image/lib/Drupal/image/ImageStyleListController.php
+++ b/core/modules/image/lib/Drupal/image/ImageStyleListController.php
@@ -10,9 +10,11 @@
 use Drupal\Core\Config\Entity\ConfigEntityListController;
 use Drupal\Core\Entity\EntityControllerInterface;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProviderInterface;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Routing\UrlGeneratorInterface;
+use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\StringTranslation\Translator\TranslatorInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -37,13 +39,17 @@ class ImageStyleListController extends ConfigEntityListController implements Ent
    *   An array of entity info for the entity type.
    * @param \Drupal\Core\Entity\EntityStorageControllerInterface $image_style_storage
    *   The image style entity storage controller class.
+   * @param \Drupal\Core\Entity\EntityOperationsProviderInterface $operations
+   *   The entity operations provider.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke hooks on.
+   * @param |Drupal\Core\Session\AccountInterface $current_user
+   *   The current user.
    * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
    *   The URL generator.
    */
-  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $image_style_storage, ModuleHandlerInterface $module_handler, UrlGeneratorInterface $url_generator) {
-    parent::__construct($entity_type, $entity_info, $image_style_storage, $module_handler);
+  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $image_style_storage, EntityOperationsProviderInterface $operations, ModuleHandlerInterface $module_handler, AccountInterface $current_user, UrlGeneratorInterface $url_generator) {
+    parent::__construct($entity_type, $entity_info, $image_style_storage, $operations, $module_handler, $current_user);
     $this->urlGenerator = $url_generator;
   }
 
@@ -55,7 +61,9 @@ public static function createInstance(ContainerInterface $container, $entity_typ
       $entity_type,
       $entity_info,
       $container->get('entity.manager')->getStorageController($entity_type),
+      $container->get('entity.manager')->getOperationsProvider($entity_type),
       $container->get('module_handler'),
+      $container->get('current_user'),
       $container->get('url_generator'),
       $container->get('string_translation')
     );
diff --git a/core/modules/language/lib/Drupal/language/Entity/Language.php b/core/modules/language/lib/Drupal/language/Entity/Language.php
index d4c8e1b..b6c5e35 100644
--- a/core/modules/language/lib/Drupal/language/Entity/Language.php
+++ b/core/modules/language/lib/Drupal/language/Entity/Language.php
@@ -21,6 +21,7 @@
  *   id = "language_entity",
  *   label = @Translation("Language"),
  *   controllers = {
+ *     "operations" = "Drupal\language\LanguageOperationsProvider",
  *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
  *     "list" = "Drupal\language\LanguageListController",
  *     "access" = "Drupal\language\LanguageAccessController",
diff --git a/core/modules/language/lib/Drupal/language/LanguageAccessController.php b/core/modules/language/lib/Drupal/language/LanguageAccessController.php
index 2cc17d0..f49b64d 100644
--- a/core/modules/language/lib/Drupal/language/LanguageAccessController.php
+++ b/core/modules/language/lib/Drupal/language/LanguageAccessController.php
@@ -18,6 +18,11 @@ class LanguageAccessController extends EntityAccessController {
    * {@inheritdoc}
    */
   public function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
+    // Deleting the site default language is not allowed.
+    if ($operation == 'delete' && $entity->id() == language_default()->id) {
+      return FALSE;
+    }
+
     switch ($operation) {
       case 'update':
       case 'delete':
diff --git a/core/modules/language/lib/Drupal/language/LanguageListController.php b/core/modules/language/lib/Drupal/language/LanguageListController.php
index 35724b7..54b6855 100644
--- a/core/modules/language/lib/Drupal/language/LanguageListController.php
+++ b/core/modules/language/lib/Drupal/language/LanguageListController.php
@@ -41,31 +41,6 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-    $default = language_default();
-
-    // Edit and delete path for Languages entities have a different pattern
-    // than other config entities.
-    $path = 'admin/config/regional/language';
-    if (isset($operations['edit'])) {
-      $operations['edit']['href'] = $path . '/edit/' . $entity->id();
-    }
-    if (isset($operations['delete'])) {
-      $operations['delete']['href'] = $path . '/delete/' . $entity->id();
-    }
-
-    // Deleting the site default language is not allowed.
-    if ($entity->id() == $default->id) {
-      unset($operations['delete']);
-    }
-
-    return $operations;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function buildHeader() {
     $header['label'] = t('Name');
     return $header + parent::buildHeader();
diff --git a/core/modules/language/lib/Drupal/language/LanguageOperationsProvider.php b/core/modules/language/lib/Drupal/language/LanguageOperationsProvider.php
new file mode 100644
index 0000000..6801373
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/LanguageOperationsProvider.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\language\LanguageOperationsProvider.
+ */
+
+namespace Drupal\language;
+
+use Drupal\Core\Config\Entity\ConfigEntityOperationsProvider;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Defines a entity operations controller for language entities.
+ */
+class LanguageOperationsProvider extends ConfigEntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+
+    // Edit and delete path for language entities have a different pattern
+    // than other config entities.
+    $path = 'admin/config/regional/language';
+    $operations['update']['href'] = $path . '/edit/' . $entity->id();
+    $operations['delete']['href'] = $path . '/delete/' . $entity->id();
+
+    return $operations;
+  }
+}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php
index 8b2190d..9472987 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php
@@ -76,10 +76,10 @@ function testLanguageList() {
 
     // Ensure we can't delete the default language.
     $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), 'Correct page redirection.');
-    $this->assertText(t('The default language cannot be deleted.'), 'Failed to delete the default language.');
+    $this->assertResponse('403');
 
     // Ensure 'Edit' link works.
+    $this->drupalGet('admin/config/regional/language');
     $this->clickLink(t('Edit'));
     $this->assertTitle(t('Edit language | Drupal'), 'Page title is "Edit language".');
     // Edit a language.
diff --git a/core/modules/menu/lib/Drupal/menu/MenuListController.php b/core/modules/menu/lib/Drupal/menu/MenuListController.php
index 4c5a408..6b3da33 100644
--- a/core/modules/menu/lib/Drupal/menu/MenuListController.php
+++ b/core/modules/menu/lib/Drupal/menu/MenuListController.php
@@ -39,28 +39,6 @@ public function buildRow(EntityInterface $entity) {
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-    $uri = $entity->uri();
-
-    if (isset($operations['edit'])) {
-      $operations['edit']['title'] = t('Edit menu');
-      $operations['add'] = array(
-        'title' => t('Add link'),
-        'href' => $uri['path'] . '/add',
-        'options' => $uri['options'],
-        'weight' => 20,
-      );
-    }
-    if (isset($operations['delete'])) {
-      $operations['delete']['title'] = t('Delete menu');
-    }
-    return $operations;
-  }
-
-  /**
    * Overrides \Drupal\Core\Entity\EntityListController::render();
    */
   public function render() {
diff --git a/core/modules/menu/lib/Drupal/menu/MenuOperationsProvider.php b/core/modules/menu/lib/Drupal/menu/MenuOperationsProvider.php
new file mode 100644
index 0000000..0daaf2d
--- /dev/null
+++ b/core/modules/menu/lib/Drupal/menu/MenuOperationsProvider.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\menu\MenuOperationsProvider.
+ */
+
+namespace Drupal\menu;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProvider;
+
+/**
+ * Defines a entity operations controller for menu entities.
+ */
+class MenuOperationsProvider extends EntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    $uri = $entity->uri();
+
+    $operations['update']['title'] = t('Edit menu');
+    $operations['delete']['title'] = t('Delete menu');
+    $operations['add'] = array(
+      'title' => t('Add link'),
+      'href' => $uri['path'] . '/add',
+      'options' => $uri['options'],
+      'weight' => 20,
+    );
+
+    return $operations;
+  }
+}
diff --git a/core/modules/node/lib/Drupal/node/Entity/NodeType.php b/core/modules/node/lib/Drupal/node/Entity/NodeType.php
index fb13664..0b77c8b 100644
--- a/core/modules/node/lib/Drupal/node/Entity/NodeType.php
+++ b/core/modules/node/lib/Drupal/node/Entity/NodeType.php
@@ -20,6 +20,7 @@
  *   id = "node_type",
  *   label = @Translation("Content type"),
  *   controllers = {
+ *     "operations" = "Drupal\node\NodeTypeOperationsProvider",
  *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
  *     "access" = "Drupal\node\NodeTypeAccessController",
  *     "form" = {
diff --git a/core/modules/node/lib/Drupal/node/NodeTypeListController.php b/core/modules/node/lib/Drupal/node/NodeTypeListController.php
index 0cb406f..5aa5fbc 100644
--- a/core/modules/node/lib/Drupal/node/NodeTypeListController.php
+++ b/core/modules/node/lib/Drupal/node/NodeTypeListController.php
@@ -8,6 +8,8 @@
 
 use Drupal\Core\Config\Entity\ConfigEntityListController;
 use Drupal\Core\Entity\EntityControllerInterface;
+use Drupal\Core\Entity\EntityOperationsProviderInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
@@ -37,13 +39,17 @@ class NodeTypeListController extends ConfigEntityListController implements Entit
    *   An array of entity info for the entity type.
    * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage
    *   The entity storage controller class.
+   * @param \Drupal\Core\Entity\EntityOperationsProviderInterface $operations
+   *   The entity operations provider.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke hooks on.
+   * @param |Drupal\Core\Session\AccountInterface $current_user
+   *   The current user.
    * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
    *   The url generator service.
    */
-  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler, UrlGeneratorInterface $url_generator) {
-    parent::__construct($entity_type, $entity_info, $storage, $module_handler);
+  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, EntityOperationsProviderInterface $operations, ModuleHandlerInterface $module_handler, AccountInterface $current_user, UrlGeneratorInterface $url_generator) {
+    parent::__construct($entity_type, $entity_info, $storage, $operations, $module_handler, $current_user);
     $this->urlGenerator = $url_generator;
   }
   /**
@@ -54,7 +60,9 @@ public static function createInstance(ContainerInterface $container, $entity_typ
       $entity_type,
       $entity_info,
       $container->get('entity.manager')->getStorageController($entity_type),
+      $container->get('entity.manager')->getOperationsProvider($entity_type),
       $container->get('module_handler'),
+      $container->get('current_user'),
       $container->get('url_generator')
     );
   }
@@ -86,19 +94,6 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-    // Place the edit operation after the operations added by field_ui.module
-    // which have the weights 15, 20, 25.
-    if (isset($operations['edit'])) {
-      $operations['edit']['weight'] = 30;
-    }
-    return $operations;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function render() {
     $build = parent::render();
     $build['#empty'] = t('No content types available. <a href="@link">Add content type</a>.', array(
diff --git a/core/modules/node/lib/Drupal/node/NodeTypeOperationsProvider.php b/core/modules/node/lib/Drupal/node/NodeTypeOperationsProvider.php
new file mode 100644
index 0000000..b290998
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/NodeTypeOperationsProvider.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\NodeTypeOperationsProvider.
+ */
+
+namespace Drupal\node;
+
+use Drupal\Core\Config\Entity\ConfigEntityOperationsProvider;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Defines a entity operations controller for node_type entities.
+ */
+class NodeTypeOperationsProvider extends ConfigEntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    // Place the edit operation after the operations added by field_ui.module
+    // which have the weights 15, 20, 25.
+    $operations['update']['weight'] = 30;
+
+    return $operations;
+  }
+}
diff --git a/core/modules/picture/lib/Drupal/picture/Entity/PictureMapping.php b/core/modules/picture/lib/Drupal/picture/Entity/PictureMapping.php
index f059079..064075c 100644
--- a/core/modules/picture/lib/Drupal/picture/Entity/PictureMapping.php
+++ b/core/modules/picture/lib/Drupal/picture/Entity/PictureMapping.php
@@ -19,6 +19,7 @@
  *   id = "picture_mapping",
  *   label = @Translation("Picture mapping"),
  *   controllers = {
+ *     "operations" = "Drupal\picture\PictureMappingOperationsProvider",
  *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
  *     "list" = "Drupal\picture\PictureMappingListController",
  *     "form" = {
diff --git a/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php b/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php
index ffe4c0c..5594053 100644
--- a/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php
+++ b/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php
@@ -33,19 +33,4 @@ public function buildRow(EntityInterface $entity) {
     return $row + parent::buildRow($entity);
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-    $uri = $entity->uri();
-    $operations['duplicate'] = array(
-      'title' => t('Duplicate'),
-      'href' => $uri['path'] . '/duplicate',
-      'options' => $uri['options'],
-      'weight' => 15,
-    );
-    return $operations;
-  }
-
 }
diff --git a/core/modules/picture/lib/Drupal/picture/PictureMappingOperationsProvider.php b/core/modules/picture/lib/Drupal/picture/PictureMappingOperationsProvider.php
new file mode 100644
index 0000000..ce2ea2e
--- /dev/null
+++ b/core/modules/picture/lib/Drupal/picture/PictureMappingOperationsProvider.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\picture\PictureMappingOperationsProvider.
+ */
+
+namespace Drupal\picture;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProvider;
+
+/**
+ * Defines a entity operations controller for picture_mapping entities.
+ */
+class PictureMappingOperationsProvider extends EntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    $uri = $entity->uri();
+    $operations['duplicate'] = array(
+      'title' => t('Duplicate'),
+      'href' => $uri['path'] . '/duplicate',
+      'options' => $uri['options'],
+      'weight' => 15,
+    );
+
+    return $operations;
+  }
+}
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Entity/ShortcutSet.php b/core/modules/shortcut/lib/Drupal/shortcut/Entity/ShortcutSet.php
index d826f70..2d0f033 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/Entity/ShortcutSet.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Entity/ShortcutSet.php
@@ -20,6 +20,7 @@
  *   id = "shortcut_set",
  *   label = @Translation("Shortcut set"),
  *   controllers = {
+ *     "operations" = "Drupal\shortcut\ShortcutSetOperationsProvider",
  *     "storage" = "Drupal\shortcut\ShortcutSetStorageController",
  *     "access" = "Drupal\shortcut\ShortcutSetAccessController",
  *     "list" = "Drupal\shortcut\ShortcutSetListController",
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListController.php
index 6215a87..ca66977 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListController.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListController.php
@@ -24,25 +24,6 @@ public function buildHeader() {
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-    $uri = $entity->uri();
-
-    if (isset($operations['edit'])) {
-      $operations['edit']['title'] = t('Edit menu');
-      $operations['edit']['href'] = $uri['path'] . '/edit';
-    }
-
-    $operations['list'] = array(
-      'title' => t('List links'),
-      'href' => $uri['path'],
-    );
-    return $operations;
-  }
-
-  /**
    * Overrides \Drupal\Core\Entity\EntityListController::buildRow().
    */
   public function buildRow(EntityInterface $entity) {
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetOperationsProvider.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetOperationsProvider.php
new file mode 100644
index 0000000..8df3e2e
--- /dev/null
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetOperationsProvider.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\shortcut\ShortcutSetOperationsProvider.
+ */
+
+namespace Drupal\shortcut;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProvider;
+
+/**
+ * Defines a entity operations controller for action entities.
+ */
+class ShortcutSetOperationsProvider extends EntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    $uri = $entity->uri();
+    $operations['update']['title'] = t('Edit menu');
+    $operations['update']['href'] = $uri['path'] . '/edit';
+    $operations['list'] = array(
+      'title' => t('List links'),
+      'href' => $uri['path'],
+    );
+
+    return $operations;
+  }
+}
diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php
index 05f9e57..d561d95 100644
--- a/core/modules/system/entity.api.php
+++ b/core/modules/system/entity.api.php
@@ -684,15 +684,54 @@ function hook_entity_field_info_alter(&$info, $entity_type) {
 }
 
 /**
- * Alter entity operations.
+ * Declares operations for an entity.
+ *
+ * @see \Drupal\Core\Entity\EntityOperationsProvider
  *
- * @param array $operations
- *   Operations array as returned by
- *   \Drupal\Core\Entity\EntityStorageControllerInterface::getOperations().
  * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entity on which the linked operations will be performed.
+ *
+ * @return array
+ *   The structure is identical to that of the return value of
+ *   \Drupal\Core\Entity\EntityOperationsProviderInterface::getOperations().
+ */
+function hook_entity_operations(\Drupal\Core\Entity\EntityInterface $entity) {
+  $uri = $entity->uri();
+  $operations['translate'] = array(
+    'title' => t('Translate'),
+    'href' => $uri['path'] . '/translate',
+    'weight' => 50,
+  );
+
+  return $operations;
+}
+
+/**
+ * Declares operations for an entity of a specific type.
+ *
+ * @see \Drupal\Core\Entity\EntityOperationsProvider
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *
+ * @return array
+ *   The structure is identical to that of the return value of
+ *   \Drupal\Core\Entity\EntityOperationsProviderInterface::getOperations().
  */
-function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\EntityInterface $entity) {
+function hook_ENTITY_TYPE_operations(\Drupal\Core\Entity\EntityInterface $entity) {
+  return array();
+}
+
+/**
+ * Alters entity operations.
+ *
+ * @see \Drupal\Core\Entity\EntityOperationsProvider
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity on which the linked operations will be performed.
+  * @param array $operations
+  *   Operations array as returned by
+  *   \Drupal\Core\Entity\EntityStorageControllerInterface::getOperations().
+  */
+function hook_entity_operations_alter(\Drupal\Core\Entity\EntityInterface $entity, array &$operations) {
   $uri = $entity->uri();
   $operations['translate'] = array(
     'title' => t('Translate'),
@@ -702,6 +741,20 @@ function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\Ent
 }
 
 /**
+ * Alters entity operations for an entity of a specific type.
+ *
+ * @see \Drupal\Core\Entity\EntityOperationsProvider
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity on which the linked operations will be performed.
+  * @param array $operations
+  *   Operations array as returned by
+  *   \Drupal\Core\Entity\EntityStorageControllerInterface::getOperations().
+  */
+function hook_ENTITY_TYPE_operations_alter(\Drupal\Core\Entity\EntityInterface $entity, array &$operations) {
+}
+
+/**
  * Control access to fields.
  *
  * This hook is invoked from
diff --git a/core/modules/system/lib/Drupal/system/DateFormatListController.php b/core/modules/system/lib/Drupal/system/DateFormatListController.php
index d22642b..d87f2a4 100644
--- a/core/modules/system/lib/Drupal/system/DateFormatListController.php
+++ b/core/modules/system/lib/Drupal/system/DateFormatListController.php
@@ -11,8 +11,10 @@
 use Drupal\Core\Config\Entity\ConfigEntityListController;
 use Drupal\Core\Datetime\Date;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProviderInterface;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -36,13 +38,17 @@ class DateFormatListController extends ConfigEntityListController {
    *   An array of entity info for the entity type.
    * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage
    *   The entity storage controller class.
+   * @param \Drupal\Core\Entity\EntityOperationsProviderInterface $operations
+   *   The entity operations provider.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke hooks on.
+   * @param |Drupal\Core\Session\AccountInterface $current_user
+   *   The current user.
    * @param \Drupal\Core\Datetime\Date $date_service
    *   The date service.
    */
-  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler, Date $date_service) {
-    parent::__construct($entity_type, $entity_info, $storage, $module_handler);
+  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, EntityOperationsProviderInterface $operations, ModuleHandlerInterface $module_handler, AccountInterface $current_user, Date $date_service) {
+    parent::__construct($entity_type, $entity_info, $storage, $operations, $module_handler, $current_user);
 
     $this->dateService = $date_service;
   }
@@ -55,7 +61,9 @@ public static function createInstance(ContainerInterface $container, $entity_typ
       $entity_type,
       $entity_info,
       $container->get('entity.manager')->getStorageController($entity_type),
+      $container->get('entity.manager')->getOperationsProvider($entity_type),
       $container->get('module_handler'),
+      $container->get('current_user'),
       $container->get('date')
     );
   }
diff --git a/core/modules/system/lib/Drupal/system/Entity/Action.php b/core/modules/system/lib/Drupal/system/Entity/Action.php
index 4962a92..da1e65e 100644
--- a/core/modules/system/lib/Drupal/system/Entity/Action.php
+++ b/core/modules/system/lib/Drupal/system/Entity/Action.php
@@ -22,6 +22,7 @@
  *   id = "action",
  *   label = @Translation("Action"),
  *   controllers = {
+ *     "operations" = "Drupal\action\ActionOperationsProvider",
  *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
  *   },
  *   admin_permission = "administer actions",
diff --git a/core/modules/system/lib/Drupal/system/Entity/DateFormat.php b/core/modules/system/lib/Drupal/system/Entity/DateFormat.php
index fb4c7d3..9516a99 100644
--- a/core/modules/system/lib/Drupal/system/Entity/DateFormat.php
+++ b/core/modules/system/lib/Drupal/system/Entity/DateFormat.php
@@ -21,6 +21,7 @@
  *   id = "date_format",
  *   label = @Translation("Date format"),
  *   controllers = {
+ *     "operations" = "\Drupal\Core\Config\Entity\ConfigEntityOperationsProvider",
  *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
  *     "access" = "Drupal\system\DateFormatAccessController",
  *     "list" = "Drupal\system\DateFormatListController",
diff --git a/core/modules/system/lib/Drupal/system/Entity/Menu.php b/core/modules/system/lib/Drupal/system/Entity/Menu.php
index 5f6d075..ac93af2 100644
--- a/core/modules/system/lib/Drupal/system/Entity/Menu.php
+++ b/core/modules/system/lib/Drupal/system/Entity/Menu.php
@@ -19,6 +19,7 @@
  *   id = "menu",
  *   label = @Translation("Menu"),
  *   controllers = {
+ *     "operations" = "Drupal\menu\MenuOperationsProvider",
  *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
  *     "access" = "Drupal\system\MenuAccessController"
  *   },
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityOperationsTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityOperationsTest.php
index 776021d..424b290 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityOperationsTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityOperationsTest.php
@@ -40,11 +40,11 @@ public function setUp() {
   }
 
   /**
-   * Checks that hook_entity_operation_alter() can add an operation.
+   * Checks that hook_entity_operations() can add an operation.
    *
-   * @see entity_test_entity_operation_alter()
+   * @see entity_test_entity_operations()
    */
-  public function testEntityOperationAlter() {
+  public function testEntityOperations() {
     // Check that role listing contain our test_operation operation.
     $this->drupalGet('admin/people/roles');
     $roles = user_roles();
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index c8f868e..6a06ee5 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -455,15 +455,17 @@ function entity_test_entity_predelete(EntityInterface $entity) {
 }
 
 /**
- * Implements hook_entity_operation_alter().
+ * Implements hook_entity_operations().
  */
-function entity_test_entity_operation_alter(array &$operations, EntityInterface $entity) {
+function entity_test_entity_operations(EntityInterface $entity) {
   $uri = $entity->uri();
   $operations['test_operation'] = array(
     'title' => format_string('Test Operation: @label', array('@label' => $entity->label())),
     'href' => $uri['path'] . '/test_operation',
     'weight' => 50,
   );
+
+  return $operations;
 }
 
 /**
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Vocabulary.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Vocabulary.php
index fe6669b..b0a522b 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Vocabulary.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Entity/Vocabulary.php
@@ -20,6 +20,7 @@
  *   id = "taxonomy_vocabulary",
  *   label = @Translation("Taxonomy vocabulary"),
  *   controllers = {
+ *     "operations" = "Drupal\taxonomy\VocabularyOperationsProvider",
  *     "storage" = "Drupal\taxonomy\VocabularyStorageController",
  *     "list" = "Drupal\taxonomy\VocabularyListController",
  *     "form" = {
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListController.php
index ff93ede..eb0ed5f 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListController.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListController.php
@@ -30,35 +30,6 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-    $uri = $entity->uri();
-
-    if (isset($operations['edit'])) {
-      $operations['edit']['title'] = t('edit vocabulary');
-      $operations['edit']['href'] = $uri['path'] . '/edit';
-    }
-
-    $operations['list'] = array(
-      'title' => t('list terms'),
-      'href' => $uri['path'],
-      'options' => $uri['options'],
-      'weight' => 0,
-    );
-    $operations['add'] = array(
-      'title' => t('add terms'),
-      'href' => $uri['path'] . '/add',
-      'options' => $uri['options'],
-      'weight' => 10,
-    );
-    unset($operations['delete']);
-
-    return $operations;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function buildHeader() {
     $header['label'] = t('Vocabulary name');
     return $header + parent::buildHeader();
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyOperationsProvider.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyOperationsProvider.php
new file mode 100644
index 0000000..1080c26
--- /dev/null
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyOperationsProvider.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\taxonomy\VocabularyOperationsProvider.
+ */
+
+namespace Drupal\taxonomy;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProvider;
+
+/**
+ * Defines a entity operations controller for taxonomy_vocabulary entities.
+ */
+class VocabularyOperationsProvider extends EntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    $uri = $entity->uri();
+
+    $operations['update']['title'] = t('edit vocabulary');
+    $operations['update']['href'] = $uri['path'] . '/edit';
+    $operations['list'] = array(
+      'title' => t('list terms'),
+      'href' => $uri['path'],
+      'options' => $uri['options'],
+      'weight' => 0,
+    );
+    $operations['add'] = array(
+      'title' => t('add terms'),
+      'href' => $uri['path'] . '/add',
+      'options' => $uri['options'],
+      'weight' => 10,
+    );
+    unset($operations['delete']);
+
+    return $operations;
+  }
+}
diff --git a/core/modules/user/lib/Drupal/user/Entity/Role.php b/core/modules/user/lib/Drupal/user/Entity/Role.php
index d58a358..10f1996 100644
--- a/core/modules/user/lib/Drupal/user/Entity/Role.php
+++ b/core/modules/user/lib/Drupal/user/Entity/Role.php
@@ -18,6 +18,7 @@
  *   id = "user_role",
  *   label = @Translation("Role"),
  *   controllers = {
+ *     "operations" = "Drupal\user\RoleOperationsProvider",
  *     "storage" = "Drupal\user\RoleStorageController",
  *     "access" = "Drupal\user\RoleAccessController",
  *     "list" = "Drupal\user\RoleListController",
diff --git a/core/modules/user/lib/Drupal/user/RoleListController.php b/core/modules/user/lib/Drupal/user/RoleListController.php
index 4aa4f52..51e7f08 100644
--- a/core/modules/user/lib/Drupal/user/RoleListController.php
+++ b/core/modules/user/lib/Drupal/user/RoleListController.php
@@ -41,24 +41,6 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-
-    $operations['permissions'] = array(
-      'title' => t('Edit permissions'),
-      'href' => 'admin/people/permissions/' . $entity->id(),
-      'weight' => 20,
-    );
-    // Built-in roles could not be deleted or disabled.
-    if (in_array($entity->id(), array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
-      unset($operations['delete']);
-    }
-    return $operations;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function submitForm(array &$form, array &$form_state) {
     parent::submitForm($form, $form_state);
 
diff --git a/core/modules/user/lib/Drupal/user/RoleOperationsProvider.php b/core/modules/user/lib/Drupal/user/RoleOperationsProvider.php
new file mode 100644
index 0000000..804e2c2
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/RoleOperationsProvider.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\RoleOperationsProvider.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityOperationsProvider;
+
+/**
+ * Defines a entity operations controller for user_role entities.
+ */
+class RoleOperationsProvider extends EntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    $operations['permissions'] = array(
+      'title' => t('Edit permissions'),
+      'href' => 'admin/people/permissions/' . $entity->id(),
+      'weight' => 20,
+    );
+
+    return $operations;
+  }
+}
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php
index ef88707..84ceecc 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php
@@ -12,8 +12,10 @@
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Config\Entity\ConfigEntityListController;
 use Drupal\Core\Entity\EntityControllerInterface;
+use Drupal\Core\Entity\EntityOperationsProviderInterface;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -35,9 +37,11 @@ public static function createInstance(ContainerInterface $container, $entity_typ
     return new static(
       $entity_type,
       $container->get('entity.manager')->getStorageController($entity_type),
+      $container->get('entity.manager')->getOperationsProvider($entity_type),
       $entity_info,
       $container->get('plugin.manager.views.display'),
-      $container->get('module_handler')
+      $container->get('module_handler'),
+      $container->get('current_user')
     );
   }
 
@@ -48,15 +52,19 @@ public static function createInstance(ContainerInterface $container, $entity_typ
    *   The type of entity to be listed.
    * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage.
    *   The entity storage controller class.
+   * @param \Drupal\Core\Entity\EntityOperationsProviderInterface $operations
+   *   The entity operations provider.
    * @param array $entity_info
    *   An array of entity info for this entity type.
    * @param \Drupal\Component\Plugin\PluginManagerInterface $display_manager
    *   The views display plugin manager to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param |Drupal\Core\Session\AccountInterface $current_user
+   *   The current user.
    */
-  public function __construct($entity_type, EntityStorageControllerInterface $storage, $entity_info, PluginManagerInterface $display_manager, ModuleHandlerInterface $module_handler) {
-    parent::__construct($entity_type, $entity_info, $storage, $module_handler);
+  public function __construct($entity_type, EntityStorageControllerInterface $storage, EntityOperationsProviderInterface $operations, $entity_info, PluginManagerInterface $display_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user) {
+    parent::__construct($entity_type, $entity_info, $storage, $operations, $module_handler, $current_user);
 
     $this->displayManager = $display_manager;
   }
@@ -140,31 +148,6 @@ public function buildHeader() {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-    $uri = $entity->uri();
-
-    $operations['clone'] = array(
-      'title' => $this->t('Clone'),
-      'href' => $uri['path'] . '/clone',
-      'options' => $uri['options'],
-      'weight' => 15,
-    );
-
-    // Add AJAX functionality to enable/disable operations.
-    foreach (array('enable', 'disable') as $op) {
-      if (isset($operations[$op])) {
-        $operations[$op]['ajax'] = TRUE;
-        $operations[$op]['query']['token'] = drupal_get_token($op);
-      }
-    }
-
-    return $operations;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function buildOperations(EntityInterface $entity) {
     $build = parent::buildOperations($entity);
 
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewOperationsProvider.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewOperationsProvider.php
new file mode 100644
index 0000000..e6da725
--- /dev/null
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewOperationsProvider.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views_ui\ViewOperationsProvider.
+ */
+
+namespace Drupal\views_ui;
+
+use Drupal\Core\Config\Entity\ConfigEntityOperationsProvider;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Defines a entity operations controller for view entities.
+ */
+class ViewOperationsProvider extends ConfigEntityOperationsProvider {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    $uri = $entity->uri();
+    $operations['clone'] = array(
+      'title' => $this->translationManager->translate('Clone'),
+      'href' => $uri['path'] . '/clone',
+      'options' => $uri['options'],
+      'weight' => 15,
+    );
+    // Add AJAX functionality to enable/disable operations.
+    foreach (array('enable', 'disable') as $operation) {
+      // @todo There is no generic access control for enable and disable
+      // operations yet. Once that is done, this if statement can be removed.
+      if (isset($operations[$operation])) {
+        $operations[$operation]['ajax'] = TRUE;
+        $operations[$operation]['query']['token'] = drupal_get_token($operation);
+      }
+    }
+
+    return $operations;
+  }
+
+
+
+}
diff --git a/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListControllerTest.php b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListControllerTest.php
index b30bb34..4dd1596 100644
--- a/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListControllerTest.php
+++ b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListControllerTest.php
@@ -124,9 +124,21 @@ public function testBuildRowEntityList() {
       ->disableOriginalConstructor()
       ->getMock();
 
+    $operations = $this->getMock('\Drupal\Core\Entity\EntityOperationsProviderInterface');
+    $operations->expects($this->once())
+      ->method('getOperations')
+      ->will($this->returnValue(array(
+        'foo' => array(
+          'href' => 'bar',
+          'title' => 'Baz',
+        ),
+      )));
+
+    $current_user = $this->getMock('\Drupal\Core\Session\AccountInterface');
+
     // Setup a view list controller with a mocked buildOperations method,
     // because t() is called on there.
-    $view_list_controller = $this->getMock('Drupal\views_ui\ViewListController', array('buildOperations'), array('view', $storage_controller, $entity_info, $display_manager, $module_handler));
+    $view_list_controller = $this->getMock('Drupal\views_ui\ViewListController', array('buildOperations'), array('view', $storage_controller, $operations, $entity_info, $display_manager, $module_handler, $current_user));
     $view_list_controller->expects($this->any())
       ->method('buildOperations')
       ->will($this->returnValue(array()));
diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module
index 93742a4..b55650d 100644
--- a/core/modules/views_ui/views_ui.module
+++ b/core/modules/views_ui/views_ui.module
@@ -51,6 +51,7 @@ function views_ui_menu() {
  */
 function views_ui_entity_info(&$entity_info) {
   $entity_info['view']['controllers'] += array(
+    'operations' => 'Drupal\views_ui\ViewOperationsProvider',
     'list' => 'Drupal\views_ui\ViewListController',
     'form' => array(
       'edit' => 'Drupal\views_ui\ViewEditFormController',
diff --git a/core/tests/Drupal/Tests/Core/Entity/ConfigEntityOperationsProviderUnitTest.php b/core/tests/Drupal/Tests/Core/Entity/ConfigEntityOperationsProviderUnitTest.php
new file mode 100644
index 0000000..5dac4bf
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Entity/ConfigEntityOperationsProviderUnitTest.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\EntityOperationsProviderUnitTest.
+ */
+
+namespace Drupal\Tests\Core\Entity;
+
+use Drupal\Core\Entity\EntityOperationsProvider;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests \Drupal\Core\Entity\EntityOperationsProvider.
+ */
+class EntityOperationsProviderUnitTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'description' => '',
+      'group' => 'Configuration',
+      'name' => '\Drupal\Core\Entity\EntityOperationsProvider',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $this->moduleHandler = $this->getMock('\Drupal\Core\Extension\ModuleHandlerInterface');
+    $this->moduleHandler->expects($this->exactly(2))
+      ->method('invokeAll')
+      ->will($this->returnValue(array()));
+
+    $this->currentUser = $this->getMock('\Drupal\Core\Session\AccountInterface');
+
+    $this->translationManager = $this->getMockBuilder('\Drupal\Core\StringTranslation\TranslationManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $this->entity = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityInterface');
+    $this->entity->expects($this->any())
+      ->method('access')
+      ->will($this->returnValue(TRUE));
+
+    $this->operationsProvider = new EntityOperationsProvider($this->moduleHandler, $this->translationManager);
+  }
+
+  /**
+   * Tests getOperations().
+   */
+  public function testGetOperations() {
+    $operations = $this->operationsProvider->getOperations($this->entity, $this->currentUser);
+    $this->assertInternalType('array', $operations);
+    $this->assertArrayHasKey('update', $operations);
+    $this->assertInternalType('array', $operations['update']);
+    $this->assertArrayHasKey('delete', $operations);
+    $this->assertInternalType('array', $operations['delete']);
+  }
+}
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityListControllerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityListControllerTest.php
index c8b07d6..d5841a2 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityListControllerTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityListControllerTest.php
@@ -74,11 +74,23 @@ protected function setUp() {
       ->disableOriginalConstructor()
       ->getMock();
 
+    $operations = $this->getMock('\Drupal\Core\Entity\EntityOperationsProviderInterface');
+    $operations->expects($this->once())
+      ->method('getOperations')
+      ->will($this->returnValue(array(
+        'foo' => array(
+          'href' => 'bar',
+          'title' => 'Baz',
+        ),
+      )));
+
+    $current_user = $this->getMock('\Drupal\Core\Session\AccountInterface');
+
     $module_handler = $this->getMockBuilder('Drupal\Core\Extension\ModuleHandler')
       ->disableOriginalConstructor()
       ->getMock();
 
-    $this->entityListController = $this->getMock('Drupal\entity_test\EntityTestListController', array('buildOperations'), array('user_role', static::$entityInfo, $role_storage_controller, $module_handler));
+    $this->entityListController = $this->getMock('Drupal\entity_test\EntityTestListController', array('buildOperations'), array('user_role', static::$entityInfo, $role_storage_controller, $operations, $module_handler, $current_user));
 
     $this->entityListController->expects($this->any())
       ->method('buildOperations')
