diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListBuilder.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListBuilder.php
index b42e63ae75fe7c71ee1815db90724adc774958cd..2bf8807a0c8566a5e89c0f27e991f8c91a3e7001 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListBuilder.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListBuilder.php
@@ -30,8 +30,9 @@ public function load() {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public function getDefaultOperations(EntityInterface $entity) {
+    /** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $entity */
+    $operations = parent::getDefaultOperations($entity);
 
     if ($this->entityType->hasKey('status')) {
       if (!$entity->status() && $entity->hasLinkTemplate('enable')) {
diff --git a/core/lib/Drupal/Core/Entity/EntityListBuilder.php b/core/lib/Drupal/Core/Entity/EntityListBuilder.php
index 33a400883388055454458c3258476f7ce5ba3689..b7b1347c9842db6fe12f754b272d8f321c41a443 100644
--- a/core/lib/Drupal/Core/Entity/EntityListBuilder.php
+++ b/core/lib/Drupal/Core/Entity/EntityListBuilder.php
@@ -93,6 +93,25 @@ protected function getLabel(EntityInterface $entity) {
    * {@inheritdoc}
    */
   public function getOperations(EntityInterface $entity) {
+    $operations = $this->getDefaultOperations($entity);
+    $operations += $this->moduleHandler()->invokeAll('entity_operation', array($entity));
+    $this->moduleHandler->alter('entity_operation', $operations, $entity);
+    uasort($operations, '\Drupal\Component\Utility\SortArray::sortByWeightElement');
+
+    return $operations;
+  }
+
+  /**
+   * Gets this list's default operations.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity the operations are for.
+   *
+   * @return array
+   *   The array structure is identical to the return value of
+   *   self::getOperations().
+   */
+  protected function getDefaultOperations(EntityInterface $entity) {
     $operations = array();
     if ($entity->access('update') && $entity->hasLinkTemplate('edit-form')) {
       $operations['edit'] = array(
@@ -151,14 +170,11 @@ public function buildRow(EntityInterface $entity) {
    * @see \Drupal\Core\Entity\EntityListBuilder::buildRow()
    */
   public function buildOperations(EntityInterface $entity) {
-    // Retrieve and sort operations.
-    $operations = $this->getOperations($entity);
-    $this->moduleHandler()->alter('entity_operation', $operations, $entity);
-    uasort($operations, array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
     $build = array(
       '#type' => 'operations',
-      '#links' => $operations,
+      '#links' => $this->getOperations($entity),
     );
+
     return $build;
   }
 
diff --git a/core/modules/action/lib/Drupal/action/ActionListBuilder.php b/core/modules/action/lib/Drupal/action/ActionListBuilder.php
index 446cc97531813cb1d8090ba40fa7ea8ca05edffb..2d3af861778a7adf72e4f56c59b73883cd4c2417 100644
--- a/core/modules/action/lib/Drupal/action/ActionListBuilder.php
+++ b/core/modules/action/lib/Drupal/action/ActionListBuilder.php
@@ -101,8 +101,8 @@ public function buildHeader() {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = $entity->isConfigurable() ? parent::getOperations($entity) : array();
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = $entity->isConfigurable() ? parent::getDefaultOperations($entity) : array();
     if (isset($operations['edit'])) {
       $operations['edit']['title'] = t('Configure');
     }
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListBuilder.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListBuilder.php
index 94c9e31e629d80ae637c8c5908c8d22045e30105..5df5a1948b51d2103c2b68084ea67314e7152a3e 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListBuilder.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockListBuilder.php
@@ -36,8 +36,8 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
     if (isset($operations['edit'])) {
       $operations['edit']['query']['destination'] = 'admin/structure/block/custom-blocks';
     }
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListBuilder.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListBuilder.php
index 8c84de45bf31da31279b9d67ecd6e373071b5e5c..723ea71e9430495766ea33cc44128948b84e6620 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListBuilder.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListBuilder.php
@@ -21,8 +21,8 @@ class CustomBlockTypeListBuilder extends ConfigEntityListBuilder {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public 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.
     if (isset($operations['edit'])) {
diff --git a/core/modules/block/lib/Drupal/block/BlockListBuilder.php b/core/modules/block/lib/Drupal/block/BlockListBuilder.php
index 8db9c6ac99c9d29f2ef76a258db2e51530287bc7..aa40a4edf8c11282859620828776c9d44be1d18e 100644
--- a/core/modules/block/lib/Drupal/block/BlockListBuilder.php
+++ b/core/modules/block/lib/Drupal/block/BlockListBuilder.php
@@ -378,8 +378,8 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
 
     if (isset($operations['edit'])) {
       $operations['edit']['title'] = t('Configure');
diff --git a/core/modules/config_translation/config_translation.module b/core/modules/config_translation/config_translation.module
index 0db169eb131164c9332554c8410f248bfc27e464..74047f71b4f753e341ac09d99b210aa24defcdfb 100644
--- a/core/modules/config_translation/config_translation.module
+++ b/core/modules/config_translation/config_translation.module
@@ -144,15 +144,18 @@ function config_translation_config_translation_info(&$info) {
 }
 
 /**
- * Implements hook_entity_operation_alter().
+ * Implements hook_entity_operation().
  */
-function config_translation_entity_operation_alter(array &$operations, EntityInterface $entity) {
+function config_translation_entity_operation(EntityInterface $entity) {
+  $operations = array();
   if (\Drupal::currentUser()->hasPermission('translate configuration')) {
     $operations['translate'] = array(
       'title' => t('Translate'),
       'weight' => 50,
     ) + $entity->urlInfo('drupal:config-translation-overview')->toArray();
   }
+
+  return $operations;
 }
 
 /**
diff --git a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListBuilder.php b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListBuilder.php
index 44f5aad2be4fd1411deddd9e3355764193fe6278..9d94468e234bf23f41e8192974985031064ec8a1 100644
--- a/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListBuilder.php
+++ b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationEntityListBuilder.php
@@ -83,13 +83,13 @@ public function buildHeader() {
   /**
    * {@inheritdoc}
    */
-  public function buildOperations(EntityInterface $entity) {
-    $operations = parent::buildOperations($entity);
-    foreach (array_keys($operations['#links']) as $operation) {
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
+    foreach (array_keys($operations) as $operation) {
       // This is a translation UI for translators. Show the translation
       // operation only.
       if (!($operation == 'translate')) {
-        unset($operations['#links'][$operation]);
+        unset($operations[$operation]);
       }
     }
     return $operations;
diff --git a/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php b/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php
index 854d80e886bf35bbe419f5358b8aadd85ed4c866..3905e86085a7c53d40dde5447c4e184237167358 100644
--- a/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php
+++ b/core/modules/field/lib/Drupal/field/Entity/FieldInstanceConfig.php
@@ -23,6 +23,7 @@
  *   id = "field_instance_config",
  *   label = @Translation("Field instance"),
  *   controllers = {
+ *     "list_builder" = "\Drupal\field_ui\FieldInstanceConfigListBuilder",
  *     "storage" = "Drupal\field\FieldInstanceConfigStorage"
  *   },
  *   config_prefix = "instance",
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 21772e174ba6d6b6b30b4fafb8963d19d42e099f..b73efed25e5adb668a51573a3d33eb4e2d736e74 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -159,9 +159,10 @@ function field_ui_form_node_type_form_alter(&$form, $form_state) {
 }
 
 /**
- * Implements hook_entity_operation_alter().
+ * Implements hook_entity_operation().
  */
-function field_ui_entity_operation_alter(array &$operations, EntityInterface $entity) {
+function field_ui_entity_operation(EntityInterface $entity) {
+  $operations = array();
   $info = $entity->getEntityType();
   // Add manage fields and display links if this entity type is the bundle
   // of another.
@@ -185,6 +186,8 @@ function field_ui_entity_operation_alter(array &$operations, EntityInterface $en
       ) + $entity->urlInfo('field_ui-display')->toArray();
     }
   }
+
+  return $operations;
 }
 
 /**
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldInstanceConfigListBuilder.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldInstanceConfigListBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..c492d54528ff762e1da380f68492161414891478
--- /dev/null
+++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldInstanceConfigListBuilder.php
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\field_ui\FieldInstanceConfigListBuilder.
+ */
+
+namespace Drupal\field_ui;
+
+use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides lists of field instance config entities.
+ */
+class FieldInstanceConfigListBuilder extends ConfigEntityListBuilder {
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
+   * Constructs a new class instance.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type definition.
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   */
+  public function __construct(EntityTypeInterface $entity_type, EntityManagerInterface $entity_manager) {
+    parent::__construct($entity_type, $entity_manager->getStorage($entity_type->id()));
+    $this->entityManager = $entity_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
+    return new static($entity_type, $container->get('entity.manager'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render() {
+    // The actual field instance config overview is rendered by
+    // \Drupal\field_ui\FieldOverview, so we should not use this class to build
+    // lists.
+    throw new \Exception('This class is only used for operations and not for building lists.');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefaultOperations(EntityInterface $entity) {
+    /** @var \Drupal\field\FieldInstanceConfigInterface $entity */
+    $operations = parent::getDefaultOperations($entity);
+
+    $target_entity_type_bundle_entity_type_id = $this->entityManager->getDefinition($entity->getTargetEntityTypeId())->getBundleEntityType();
+    $route_parameters = array(
+      $target_entity_type_bundle_entity_type_id => $entity->targetBundle(),
+      'field_instance_config' => $entity->id(),
+    );
+    $operations['edit'] = array(
+      'title' => $this->t('Edit'),
+      'route_name' => 'field_ui.instance_edit_' . $entity->getTargetEntityTypeId(),
+      'route_parameters' => $route_parameters,
+      'attributes' => array('title' => $this->t('Edit instance settings.')),
+    );
+    $operations['field-settings'] = array(
+      'title' => $this->t('Field settings'),
+      'route_name' => 'field_ui.field_edit_' . $entity->getTargetEntityTypeId(),
+      'route_parameters' => $route_parameters,
+      'attributes' => array('title' => $this->t('Edit field settings.')),
+    );
+    $operations['delete'] = array(
+      'title' => $this->t('Delete'),
+      'route_name' => 'field_ui.delete_' . $entity->getTargetEntityTypeId(),
+      'route_parameters' => $route_parameters,
+      'attributes' => array('title' => $this->t('Delete instance.')),
+    );
+
+    return $operations;
+  }
+
+}
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php
index 51f15e94c6192721aaffb0d00986a6666e34da2a..523f1b046e203a68253331ae630c6b7a6a6f3368 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\field_ui;
 
+use Drupal\Core\Entity\EntityListBuilderInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
@@ -27,13 +28,6 @@ class FieldOverview extends OverviewBase {
    */
   protected $fieldTypeManager;
 
-  /**
-   * The module handler service.
-   *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface
-   */
-  protected $moduleHandler;
-
   /**
    * Constructs a new FieldOverview.
    *
@@ -41,13 +35,10 @@ class FieldOverview extends OverviewBase {
    *   The entity manager.
    * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
    *   The field type manager
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler to invoke hooks on.
    */
-  public function __construct(EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager, ModuleHandlerInterface $module_handler) {
+  public function __construct(EntityManagerInterface $entity_manager, FieldTypePluginManagerInterface $field_type_manager) {
     parent::__construct($entity_manager);
     $this->fieldTypeManager = $field_type_manager;
-    $this->moduleHandler = $module_handler;
   }
 
   /**
@@ -56,8 +47,7 @@ public function __construct(EntityManagerInterface $entity_manager, FieldTypePlu
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('entity.manager'),
-      $container->get('plugin.manager.field.field_type'),
-      $container->get('module_handler')
+      $container->get('plugin.manager.field.field_type')
     );
   }
 
@@ -146,30 +136,9 @@ public function buildForm(array $form, array &$form_state, $entity_type_id = NUL
         ),
       );
 
-      $links = array();
-      $links['edit'] = array(
-        'title' => $this->t('Edit'),
-        'route_name' => 'field_ui.instance_edit_' . $this->entity_type,
-        'route_parameters' => $route_parameters,
-        'attributes' => array('title' => $this->t('Edit instance settings.')),
-      );
-      $links['field-settings'] = array(
-        'title' => $this->t('Field settings'),
-        'route_name' => 'field_ui.field_edit_' . $this->entity_type,
-        'route_parameters' => $route_parameters,
-        'attributes' => array('title' => $this->t('Edit field settings.')),
-      );
-      $links['delete'] = array(
-        'title' => $this->t('Delete'),
-        'route_name' => 'field_ui.delete_' . $this->entity_type,
-        'route_parameters' => $route_parameters,
-        'attributes' => array('title' => $this->t('Delete instance.')),
-      );
-      // Allow altering the operations on this entity listing.
-      $this->moduleHandler->alter('entity_operation', $links, $instance);
       $table[$name]['operations']['data'] = array(
         '#type' => 'operations',
-        '#links' => $links,
+        '#links' => $this->entityManager->getListBuilder('field_instance_config')->getOperations($instance),
       );
 
       if (!empty($field->locked)) {
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
index 979d68b089eabf2f3c6e226ce4f0731082dd0332..886001082c600ed94e83ec7bac6d3b1734266284 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
@@ -106,6 +106,11 @@ function manageFieldsPage($type = '') {
     foreach (array('Add new field', 'Re-use existing field') as $element) {
       $this->assertText($element, format_string('"@element" was found.', array('@element' => $element)));
     }
+
+    // Assert entity operations for all field instances.
+    $this->assertLinkByHref("admin/structure/types/manage/$type/fields/node.$type.body");
+    $this->assertLinkByHref("admin/structure/types/manage/$type/fields/node.$type.body/delete");
+    $this->assertLinkByHref("admin/structure/types/manage/$type/fields/node.$type.body/field");
   }
 
   /**
diff --git a/core/modules/filter/lib/Drupal/filter/FilterFormatListBuilder.php b/core/modules/filter/lib/Drupal/filter/FilterFormatListBuilder.php
index a22b99829ee60b46e6fac22688c10ab7be054e4b..06ad870d96d95c67f9deb93d921390ed29d29a4d 100644
--- a/core/modules/filter/lib/Drupal/filter/FilterFormatListBuilder.php
+++ b/core/modules/filter/lib/Drupal/filter/FilterFormatListBuilder.php
@@ -118,8 +118,8 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
 
     if (isset($operations['edit'])) {
       $operations['edit']['title'] = t('Configure');
diff --git a/core/modules/image/lib/Drupal/image/ImageStyleListBuilder.php b/core/modules/image/lib/Drupal/image/ImageStyleListBuilder.php
index 26642dd22c8d9c4b1a3c65742f5985f95164a172..73dfe6c80eabd82b1ec555d5d469ed932ed59ee7 100644
--- a/core/modules/image/lib/Drupal/image/ImageStyleListBuilder.php
+++ b/core/modules/image/lib/Drupal/image/ImageStyleListBuilder.php
@@ -74,13 +74,15 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
+  public function getDefaultOperations(EntityInterface $entity) {
     $flush = array(
       'title' => t('Flush'),
       'weight' => 200,
     ) + $entity->urlInfo('flush-form')->toArray();
 
-    return parent::getOperations($entity) + array('flush' => $flush);
+    return parent::getDefaultOperations($entity) + array(
+      'flush' => $flush,
+    );
   }
 
   /**
diff --git a/core/modules/language/lib/Drupal/language/LanguageListBuilder.php b/core/modules/language/lib/Drupal/language/LanguageListBuilder.php
index 99fb96791356725413863bcf8ddd68a7809bdf64..c5bd66a30f6af7bdc3fdea9113c42d40efb70eee 100644
--- a/core/modules/language/lib/Drupal/language/LanguageListBuilder.php
+++ b/core/modules/language/lib/Drupal/language/LanguageListBuilder.php
@@ -44,8 +44,8 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
     $default = language_default();
 
     // Deleting the site default language is not allowed.
diff --git a/core/modules/menu/lib/Drupal/menu/MenuListBuilder.php b/core/modules/menu/lib/Drupal/menu/MenuListBuilder.php
index b1ff07ea82a3689d9364de44e646bd9cadf3e629..b1df5df8e8ce5acd8004b1f1382604e187716dba 100644
--- a/core/modules/menu/lib/Drupal/menu/MenuListBuilder.php
+++ b/core/modules/menu/lib/Drupal/menu/MenuListBuilder.php
@@ -46,8 +46,8 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
 
     if (isset($operations['edit'])) {
       $operations['edit']['title'] = t('Edit menu');
diff --git a/core/modules/node/lib/Drupal/node/NodeListBuilder.php b/core/modules/node/lib/Drupal/node/NodeListBuilder.php
index c888155c7a018e74102d0624e83b55b3e3529511..51b24855a037fa29452fd73c29ce2b66d8c5edcc 100644
--- a/core/modules/node/lib/Drupal/node/NodeListBuilder.php
+++ b/core/modules/node/lib/Drupal/node/NodeListBuilder.php
@@ -124,8 +124,8 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  protected function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
 
     $destination = drupal_get_destination();
     foreach ($operations as $key => $operation) {
diff --git a/core/modules/node/lib/Drupal/node/NodeTypeListBuilder.php b/core/modules/node/lib/Drupal/node/NodeTypeListBuilder.php
index 9dfe6954d56c9da3fbf571a405291452fed73f5c..45bac5766f45f275a07d48b6b3f6c7ae20942e46 100644
--- a/core/modules/node/lib/Drupal/node/NodeTypeListBuilder.php
+++ b/core/modules/node/lib/Drupal/node/NodeTypeListBuilder.php
@@ -83,8 +83,8 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public 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.
     if (isset($operations['edit'])) {
diff --git a/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListBuilder.php b/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListBuilder.php
index ce1f56d73400d3bc46fc861dd87258ef310cec8f..b12fb61f8eee9310d828288c940146736eb6aa17 100644
--- a/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListBuilder.php
+++ b/core/modules/responsive_image/lib/Drupal/responsive_image/ResponsiveImageMappingListBuilder.php
@@ -36,8 +36,8 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
     $operations['duplicate'] = array(
       'title' => t('Duplicate'),
       'weight' => 15,
diff --git a/core/modules/search/lib/Drupal/search/SearchPageListBuilder.php b/core/modules/search/lib/Drupal/search/SearchPageListBuilder.php
index 6d82d201bde2e07b3171ee70c8dc1092bf0fb8ef..d9bb5e32d862fbcea412a112caa368a21a6c0f5a 100644
--- a/core/modules/search/lib/Drupal/search/SearchPageListBuilder.php
+++ b/core/modules/search/lib/Drupal/search/SearchPageListBuilder.php
@@ -260,9 +260,9 @@ public function buildForm(array $form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
+  public function getDefaultOperations(EntityInterface $entity) {
     /** @var $entity \Drupal\search\SearchPageInterface */
-    $operations = parent::getOperations($entity);
+    $operations = parent::getDefaultOperations($entity);
 
     // Prevent the default search from being disabled or deleted.
     if ($entity->isDefaultSearch()) {
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListBuilder.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListBuilder.php
index fcdfb97a0eaa6d5fced0332dfff88a95baf9dc61..907f470c65f0de89919925e7143167d1db7de237 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListBuilder.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListBuilder.php
@@ -28,8 +28,8 @@ public function buildHeader() {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
 
     if (isset($operations['edit'])) {
       $operations['edit']['title'] = t('Edit shortcut set');
diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php
index 8afd2d0d65cf8e8ccda34fe7e857ac4165ca93e9..4417e0b0e7345c3b82b7b4d9b274f8534a1ac610 100644
--- a/core/modules/system/entity.api.php
+++ b/core/modules/system/entity.api.php
@@ -756,6 +756,27 @@ function hook_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\Entit
   }
 }
 
+/**
+ * Declares entity operations.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity on which the linked operations will be performed.
+ *
+ * @return array
+ *   An operations array as returned by
+ *   \Drupal\Core\Entity\EntityListBuilderInterface::getOperations().
+ */
+function hook_entity_operation(\Drupal\Core\Entity\EntityInterface $entity) {
+  $operations = array();
+  $operations['translate'] = array(
+    'title' => t('Translate'),
+    'route_name' => 'foo_module.entity.translate',
+    'weight' => 50,
+  );
+
+  return $operations;
+}
+
 /**
  * Alter entity operations.
  *
@@ -766,10 +787,11 @@ function hook_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\Entit
  *   The entity on which the linked operations will be performed.
  */
 function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\EntityInterface $entity) {
-  $operations['translate'] = array(
-    'title' => t('Translate'),
-    'weight' => 50,
-  ) + $entity->urlInfo('my-custom-link-template')->toArray();
+  // Alter the title and weight.
+  $operations['translate']['title'] = t('Translate @entity_type', array(
+    '@entity_type' => $entity->getEntityTypeId(),
+  ));
+  $operations['translate']['weight'] = 99;
 }
 
 /**
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListBuilder.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListBuilder.php
index 1301b36d3a97d0df695ec52afb72f44557c1b488..c4fc1ad244fe4a10e94875ee758655d4f343268b 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListBuilder.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListBuilder.php
@@ -32,8 +32,8 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
 
     if (isset($operations['edit'])) {
       $operations['edit']['title'] = t('Edit vocabulary');
diff --git a/core/modules/user/lib/Drupal/user/RoleListBuilder.php b/core/modules/user/lib/Drupal/user/RoleListBuilder.php
index 0d557c7330a452dc58b4b30af14110d2b712ad51..afe8d7b0771a3a3c8f9d0378272f5ac2bd2b3dc9 100644
--- a/core/modules/user/lib/Drupal/user/RoleListBuilder.php
+++ b/core/modules/user/lib/Drupal/user/RoleListBuilder.php
@@ -43,8 +43,8 @@ public function buildRow(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
 
     if ($entity->hasLinkTemplate('edit-permissions-form')) {
       $operations['permissions'] = array(
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php
index 2adf662d404b46aa0f46e6020c3299ce7a54e29c..0242f5b2447c1e38827e08ff14fd834c0f616adc 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewListBuilder.php
@@ -135,8 +135,8 @@ public function buildHeader() {
   /**
    * {@inheritdoc}
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
+  public function getDefaultOperations(EntityInterface $entity) {
+    $operations = parent::getDefaultOperations($entity);
 
     if ($entity->hasLinkTemplate('clone')) {
       $operations['clone'] = array(
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityListBuilderTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityListBuilderTest.php
index b413675060801a2ca123fc73f220357d04cab232..f6d412949f570d9d659d1041d11d4d7863623e6e 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityListBuilderTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityListBuilderTest.php
@@ -7,7 +7,9 @@
 
 namespace Drupal\Tests\Core\Entity;
 
+use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityListBuilder;
 use Drupal\entity_test\EntityTestListBuilder;
 use Drupal\Tests\UnitTestCase;
 
@@ -20,6 +22,41 @@
  */
 class EntityListBuilderTest extends UnitTestCase {
 
+  /**
+   * The entity type used for testing.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityType;
+
+  /**
+   * The module handler used for testing.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $moduleHandler;
+
+  /**
+   * The translation manager used for testing.
+   *
+   * @var \Drupal\Core\StringTranslation\TranslationInterface
+   */
+  protected $translationManager;
+
+  /**
+   * The role storage used for testing.
+   *
+   * @var \Drupal\user\RoleStorageInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $roleStorage;
+
+  /**
+   * The service container used for testing.
+   *
+   * @var \Drupal\Core\DependencyInjection\ContainerBuilder
+   */
+  protected $container;
+
   /**
    * The entity used to construct the EntityListBuilder.
    *
@@ -49,10 +86,65 @@ protected function setUp() {
     parent::setUp();
 
     $this->role = $this->getMock('Drupal\user\RoleInterface');
-    $role_storage = $this->getMock('Drupal\user\RoleStorageInterface');
-    $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
-    $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
-    $this->entityListBuilder = new TestEntityListBuilder($entity_type, $role_storage, $module_handler);
+    $this->roleStorage = $this->getMock('\Drupal\user\RoleStorageInterface');
+    $this->moduleHandler = $this->getMock('\Drupal\Core\Extension\ModuleHandlerInterface');
+    $this->entityType = $this->getMock('\Drupal\Core\Entity\EntityTypeInterface');
+    $this->translationManager = $this->getMock('\Drupal\Core\StringTranslation\TranslationInterface');
+    $this->entityListBuilder = new TestEntityListBuilder($this->entityType, $this->roleStorage, $this->moduleHandler);
+    $this->container = new ContainerBuilder();
+    \Drupal::setContainer($this->container);
+  }
+
+  /**
+   * @covers \Drupal\Core\Entity\EntityListBuilder::getOperations
+   */
+  public function testGetOperations() {
+    $operation_name = $this->randomName();
+    $operations = array(
+      $operation_name => array(
+        'title' => $this->randomName(),
+      ),
+    );
+    $this->moduleHandler->expects($this->once())
+      ->method('invokeAll')
+      ->with('entity_operation', array($this->role))
+      ->will($this->returnValue($operations));
+    $this->moduleHandler->expects($this->once())
+      ->method('alter')
+      ->with('entity_operation');
+
+    $this->container->set('module_handler', $this->moduleHandler);
+
+    $this->role->expects($this->any())
+      ->method('access')
+      ->will($this->returnValue(TRUE));
+    $this->role->expects($this->any())
+      ->method('hasLinkTemplate')
+      ->will($this->returnValue(TRUE));
+    $url = $this->getMockBuilder('\Drupal\Core\Url')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $url->expects($this->any())
+      ->method('toArray')
+      ->will($this->returnValue(array()));
+    $this->role->expects($this->any())
+      ->method('urlInfo')
+      ->will($this->returnValue($url));
+
+    $list = new EntityListBuilder($this->entityType, $this->roleStorage, $this->moduleHandler);
+    $list->setTranslationManager($this->translationManager);
+
+    $operations = $list->getOperations($this->role);
+    $this->assertInternalType('array', $operations);
+    $this->assertArrayHasKey('edit', $operations);
+    $this->assertInternalType('array', $operations['edit']);
+    $this->assertArrayHasKey('title', $operations['edit']);
+    $this->assertArrayHasKey('delete', $operations);
+    $this->assertInternalType('array', $operations['delete']);
+    $this->assertArrayHasKey('title', $operations['delete']);
+    $this->assertArrayHasKey($operation_name, $operations);
+    $this->assertInternalType('array', $operations[$operation_name]);
+    $this->assertArrayHasKey('title', $operations[$operation_name]);
   }
 
   /**