diff --git a/core/modules/node/config/views.view.content.yml b/core/modules/node/config/views.view.content.yml
index 39f6d60b1afdc4d3a34b70268e5aab3d5fdce1f3..487b04bd61ae2c55d1a886c074c3c9755a14230e 100644
--- a/core/modules/node/config/views.view.content.yml
+++ b/core/modules/node/config/views.view.content.yml
@@ -279,6 +279,7 @@ display:
           text: Translate
           optional: '1'
           plugin_id: content_translation_link
+          provider: content_translation
         dropbutton:
           id: dropbutton
           table: views
diff --git a/core/modules/views/lib/Drupal/views/Plugin/ViewsHandlerManager.php b/core/modules/views/lib/Drupal/views/Plugin/ViewsHandlerManager.php
index 4ac2fac2442a402707aa1f36f680a17e59385bf0..0a1fb76bdba310e270da69eb045ba09004e9767f 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/ViewsHandlerManager.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/ViewsHandlerManager.php
@@ -77,7 +77,7 @@ public function __construct($handler_type, \Traversable $namespaces, ViewsData $
   public function getHandler($item, $override = NULL) {
     $table = $item['table'];
     $field = $item['field'];
-    $optional = isset($item['optional']) ? $item['optional'] : FALSE;
+    $optional = !empty($item['optional']);
     // Get the plugin manager for this type.
     $data = $this->viewsData->get($table);
 
@@ -118,7 +118,7 @@ public function getHandler($item, $override = NULL) {
     }
 
     // Finally, use the 'broken' handler.
-    return $this->createInstance('broken');
+    return $this->createInstance('broken', array('optional' => $optional, 'original_configuration' => $item));
   }
 
 }
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
index 51d3a99c819f560070f3fc296a5c62807f546704..5912c768dc351b922684f421e7cdae028a66149d 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/HandlerBase.php
@@ -76,12 +76,20 @@ abstract class HandlerBase extends PluginBase {
    */
   public $relationship = NULL;
 
+  /**
+   * Whether or not this handler is optional.
+   *
+   * @var bool
+   */
+  protected $optional = FALSE;
+
   /**
    * Constructs a Handler object.
    */
   public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
     $this->is_handler = TRUE;
+    $this->optional = !empty($configuration['optional']);
   }
 
   /**
@@ -151,6 +159,15 @@ protected function defineOptions() {
     return $options;
   }
 
+  /**
+   * Returns whether this handler is optional.
+   *
+   * @return bool
+   */
+  public function isOptional() {
+    return $this->optional;
+  }
+
   /**
    * Return a string representing this handler's name in the UI.
    */
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/area/Broken.php b/core/modules/views/lib/Drupal/views/Plugin/views/area/Broken.php
index 64a63a0a65b1056bd9d999c9e8c0707ad36219a7..08d30692cdaff81a824d80c706d914a07e5f056e 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/area/Broken.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/area/Broken.php
@@ -8,6 +8,7 @@
 namespace Drupal\views\Plugin\views\area;
 
 use Drupal\Component\Annotation\PluginID;
+use Drupal\views\ViewExecutable;
 
 /**
  * A special handler to take the place of missing or broken handlers.
@@ -19,7 +20,10 @@
 class Broken extends AreaPluginBase {
 
   public function adminLabel($short = FALSE) {
-    return t('Broken/missing handler');
+    $args = array(
+      '@module' => $this->definition['original_configuration']['provider'],
+    );
+    return $this->isOptional() ? t('Optional handler is missing (Module: @module) …', $args) : t('Broken/missing handler (Module: @module) …', $args);
   }
 
   public function defineOptions() { return array(); }
@@ -32,9 +36,41 @@ public function render($empty = FALSE) {
     // Simply render nothing by returning an empty render array.
     return array();
   }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildOptionsForm(&$form, &$form_state) {
-    $form['markup'] = array(
-      '#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
+    if ($this->isOptional()) {
+      $description_top = t('The handler for this item is optional. The following details are available:');
+    }
+    else {
+      $description_top = t('The handler for this item is broken or missing. The following details are available:');
+    }
+
+    $items = array(
+      t('Module: @module', array('@module' => $this->definition['original_configuration']['provider'])),
+      t('Table: @table', array('@table' => $this->definition['original_configuration']['table'])),
+      t('Field: @field', array('@field' => $this->definition['original_configuration']['field'])),
+    );
+
+    $description_bottom = t('Enabling the appropriate module will may solve this issue. Otherwise, check to see if there is a module update available.');
+
+    $form['description'] = array(
+      '#type' => 'container',
+      '#attributes' => array(
+        'class' => array('form-item', 'description'),
+      ),
+      'description_top' => array(
+        '#markup' => '<p>' . $description_top . '</p>',
+      ),
+      'detail_list' => array(
+        '#theme' => 'item_list',
+        '#items' => $items,
+      ),
+      'description_bottom' => array(
+        '#markup' => '<p>' . $description_bottom . '</p>',
+      ),
     );
   }
 
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/argument/Broken.php b/core/modules/views/lib/Drupal/views/Plugin/views/argument/Broken.php
index d74ab95897ec8852310bd9c72707863f28c6557e..1250ea3d10bf155c85943babadf1a9a03df40c47 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/argument/Broken.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/argument/Broken.php
@@ -19,15 +19,50 @@
 class Broken extends ArgumentPluginBase {
 
   public function adminLabel($short = FALSE) {
-    return t('Broken/missing handler');
+    $args = array(
+      '@module' => $this->definition['original_configuration']['provider'],
+    );
+    return $this->isOptional() ? t('Optional handler is missing (Module: @module) …', $args) : t('Broken/missing handler (Module: @module) …', $args);
   }
 
   public function defineOptions() { return array(); }
   public function ensureMyTable() { /* No table to ensure! */ }
   public function query($group_by = FALSE) { /* No query to run */ }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildOptionsForm(&$form, &$form_state) {
-    $form['markup'] = array(
-      '#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
+    if ($this->isOptional()) {
+      $description_top = t('The handler for this item is optional. The following details are available:');
+    }
+    else {
+      $description_top = t('The handler for this item is broken or missing. The following details are available:');
+    }
+
+    $items = array(
+      t('Module: @module', array('@module' => $this->definition['original_configuration']['provider'])),
+      t('Table: @table', array('@table' => $this->definition['original_configuration']['table'])),
+      t('Field: @field', array('@field' => $this->definition['original_configuration']['field'])),
+    );
+
+    $description_bottom = t('Enabling the appropriate module will may solve this issue. Otherwise, check to see if there is a module update available.');
+
+    $form['description'] = array(
+      '#type' => 'container',
+      '#attributes' => array(
+        'class' => array('form-item', 'description'),
+      ),
+      'description_top' => array(
+        '#markup' => '<p>' . $description_top . '</p>',
+      ),
+      'detail_list' => array(
+        '#theme' => 'item_list',
+        '#items' => $items,
+      ),
+      'description_bottom' => array(
+        '#markup' => '<p>' . $description_bottom . '</p>',
+      ),
     );
   }
 
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/field/Broken.php b/core/modules/views/lib/Drupal/views/Plugin/views/field/Broken.php
index 6310248f1f4b16bb64e19a2637ba4cab227d1ae6..f44871021a12d18bc28e763648b97e16b4a526b5 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/field/Broken.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/Broken.php
@@ -19,15 +19,50 @@
 class Broken extends FieldPluginBase {
 
   public function adminLabel($short = FALSE) {
-    return t('Broken/missing handler');
+    $args = array(
+      '@module' => $this->definition['original_configuration']['provider'],
+    );
+    return $this->isOptional() ? t('Optional handler is missing (Module: @module) …', $args) : t('Broken/missing handler (Module: @module) …', $args);
   }
 
   public function defineOptions() { return array(); }
   public function ensureMyTable() { /* No table to ensure! */ }
   public function query($group_by = FALSE) { /* No query to run */ }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildOptionsForm(&$form, &$form_state) {
-    $form['markup'] = array(
-      '#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
+    if ($this->isOptional()) {
+      $description_top = t('The handler for this item is optional. The following details are available:');
+    }
+    else {
+      $description_top = t('The handler for this item is broken or missing. The following details are available:');
+    }
+
+    $items = array(
+      t('Module: @module', array('@module' => $this->definition['original_configuration']['provider'])),
+      t('Table: @table', array('@table' => $this->definition['original_configuration']['table'])),
+      t('Field: @field', array('@field' => $this->definition['original_configuration']['field'])),
+    );
+
+    $description_bottom = t('Enabling the appropriate module will may solve this issue. Otherwise, check to see if there is a module update available.');
+
+    $form['description'] = array(
+      '#type' => 'container',
+      '#attributes' => array(
+        'class' => array('form-item', 'description'),
+      ),
+      'description_top' => array(
+        '#markup' => '<p>' . $description_top . '</p>',
+      ),
+      'detail_list' => array(
+        '#theme' => 'item_list',
+        '#items' => $items,
+      ),
+      'description_bottom' => array(
+        '#markup' => '<p>' . $description_bottom . '</p>',
+      ),
     );
   }
 
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/filter/Broken.php b/core/modules/views/lib/Drupal/views/Plugin/views/filter/Broken.php
index 701cabb9d8a408a20f214f17fd3007a18e00be75..4ba007743281fa85673c25a005031fa87db92e21 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/filter/Broken.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/filter/Broken.php
@@ -27,15 +27,50 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
   }
 
   public function adminLabel($short = FALSE) {
-    return t('Broken/missing handler');
+    $args = array(
+      '@module' => $this->definition['original_configuration']['provider'],
+    );
+    return $this->isOptional() ? t('Optional handler is missing (Module: @module) …', $args) : t('Broken/missing handler (Module: @module) …', $args);
   }
 
   public function defineOptions() { return array(); }
   public function ensureMyTable() { /* No table to ensure! */ }
   public function query($group_by = FALSE) { /* No query to run */ }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildOptionsForm(&$form, &$form_state) {
-    $form['markup'] = array(
-      '#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
+    if ($this->isOptional()) {
+      $description_top = t('The handler for this item is optional. The following details are available:');
+    }
+    else {
+      $description_top = t('The handler for this item is broken or missing. The following details are available:');
+    }
+
+    $items = array(
+      t('Module: @module', array('@module' => $this->definition['original_configuration']['provider'])),
+      t('Table: @table', array('@table' => $this->definition['original_configuration']['table'])),
+      t('Field: @field', array('@field' => $this->definition['original_configuration']['field'])),
+    );
+
+    $description_bottom = t('Enabling the appropriate module will may solve this issue. Otherwise, check to see if there is a module update available.');
+
+    $form['description'] = array(
+      '#type' => 'container',
+      '#attributes' => array(
+        'class' => array('form-item', 'description'),
+      ),
+      'description_top' => array(
+        '#markup' => '<p>' . $description_top . '</p>',
+      ),
+      'detail_list' => array(
+        '#theme' => 'item_list',
+        '#items' => $items,
+      ),
+      'description_bottom' => array(
+        '#markup' => '<p>' . $description_bottom . '</p>',
+      ),
     );
   }
 
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/relationship/Broken.php b/core/modules/views/lib/Drupal/views/Plugin/views/relationship/Broken.php
index c891f00fd914fa80c324f20b2fe29cffde928037..8e04bb1cd4b8abf76097fb1f8a7117f538528580 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/relationship/Broken.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/relationship/Broken.php
@@ -19,15 +19,50 @@
 class Broken extends RelationshipPluginBase {
 
   public function adminLabel($short = FALSE) {
-    return t('Broken/missing handler');
+    $args = array(
+      '@module' => $this->definition['original_configuration']['provider'],
+    );
+    return $this->isOptional() ? t('Optional handler is missing (Module: @module) …', $args) : t('Broken/missing handler (Module: @module) …', $args);
   }
 
   public function defineOptions() { return array(); }
   public function ensureMyTable() { /* No table to ensure! */ }
   public function query() { /* No query to run */ }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildOptionsForm(&$form, &$form_state) {
-    $form['markup'] = array(
-      '#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
+    if ($this->isOptional()) {
+      $description_top = t('The handler for this item is optional. The following details are available:');
+    }
+    else {
+      $description_top = t('The handler for this item is broken or missing. The following details are available:');
+    }
+
+    $items = array(
+      t('Module: @module', array('@module' => $this->definition['original_configuration']['provider'])),
+      t('Table: @table', array('@table' => $this->definition['original_configuration']['table'])),
+      t('Field: @field', array('@field' => $this->definition['original_configuration']['field'])),
+    );
+
+    $description_bottom = t('Enabling the appropriate module will may solve this issue. Otherwise, check to see if there is a module update available.');
+
+    $form['description'] = array(
+      '#type' => 'container',
+      '#attributes' => array(
+        'class' => array('form-item', 'description'),
+      ),
+      'description_top' => array(
+        '#markup' => '<p>' . $description_top . '</p>',
+      ),
+      'detail_list' => array(
+        '#theme' => 'item_list',
+        '#items' => $items,
+      ),
+      'description_bottom' => array(
+        '#markup' => '<p>' . $description_bottom . '</p>',
+      ),
     );
   }
 
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/sort/Broken.php b/core/modules/views/lib/Drupal/views/Plugin/views/sort/Broken.php
index 341bc8ba42e41e7197a6cdd968e7c8dcbc52c122..dd832dc4f1cca62371a4aa97b9432279a2f50b21 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/sort/Broken.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/sort/Broken.php
@@ -19,15 +19,50 @@
 class Broken extends SortPluginBase {
 
   public function adminLabel($short = FALSE) {
-    return t('Broken/missing handler');
+    $args = array(
+      '@module' => $this->definition['original_configuration']['provider'],
+    );
+    return $this->isOptional() ? t('Optional handler is missing (Module: @module) …', $args) : t('Broken/missing handler (Module: @module) …', $args);
   }
 
   public function defineOptions() { return array(); }
   public function ensureMyTable() { /* No table to ensure! */ }
   public function query($group_by = FALSE) { /* No query to run */ }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildOptionsForm(&$form, &$form_state) {
-    $form['markup'] = array(
-      '#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
+    if ($this->isOptional()) {
+      $description_top = t('The handler for this item is optional. The following details are available:');
+    }
+    else {
+      $description_top = t('The handler for this item is broken or missing. The following details are available:');
+    }
+
+    $items = array(
+      t('Module: @module', array('@module' => $this->definition['original_configuration']['provider'])),
+      t('Table: @table', array('@table' => $this->definition['original_configuration']['table'])),
+      t('Field: @field', array('@field' => $this->definition['original_configuration']['field'])),
+    );
+
+    $description_bottom = t('Enabling the appropriate module will may solve this issue. Otherwise, check to see if there is a module update available.');
+
+    $form['description'] = array(
+      '#type' => 'container',
+      '#attributes' => array(
+        'class' => array('form-item', 'description'),
+      ),
+      'description_top' => array(
+        '#markup' => '<p>' . $description_top . '</p>',
+      ),
+      'detail_list' => array(
+        '#theme' => 'item_list',
+        '#items' => $items,
+      ),
+      'description_bottom' => array(
+        '#markup' => '<p>' . $description_bottom . '</p>',
+      ),
     );
   }
 
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_broken.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_broken.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e5870e5024f728b31c3db0f4f77d7e79f46f367e
--- /dev/null
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_broken.yml
@@ -0,0 +1,89 @@
+base_table: views_test_data
+core: '8'
+description: ''
+status: '1'
+display:
+  default:
+    display_options:
+      defaults:
+        fields: '0'
+        pager: '0'
+        pager_options: '0'
+        sorts: '0'
+      fields:
+        id_broken:
+          field: id_broken
+          id: id_broken
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          provider: views
+      filters:
+        id_broken:
+          field: id_broken
+          id: id_broken
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          provider: views
+      arguments:
+        id_broken:
+          field: id_broken
+          id: id_broken
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          provider: views
+      sorts:
+        id_broken:
+          field: id_broken
+          id: id_broken
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          order: ASC
+          provider: views
+      relationships:
+        id_broken:
+          field: id_broken
+          id: id_broken
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          provider: views
+      header:
+        id_broken:
+          field: id_broken
+          id: id_broken
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          provider: views
+      footer:
+        id_broken:
+          field: id_broken
+          id: id_broken
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          provider: views
+      empty:
+        id_broken:
+          field: id_broken
+          id: id_broken
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          provider: views
+      pager:
+        options:
+          offset: '0'
+        type: none
+      pager_options: {  }
+    display_plugin: default
+    display_title: Master
+    id: default
+    position: '0'
+label: 'Test view'
+id: test_view_broken
+tag: ''
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_optional.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_optional.yml
new file mode 100644
index 0000000000000000000000000000000000000000..36bf93e4ae112ed4727c77432df65f044c696e94
--- /dev/null
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_view_optional.yml
@@ -0,0 +1,97 @@
+base_table: views_test_data
+core: '8'
+description: ''
+status: '1'
+display:
+  default:
+    display_options:
+      defaults:
+        fields: '0'
+        pager: '0'
+        pager_options: '0'
+        sorts: '0'
+      fields:
+        id_optional:
+          field: id_optional
+          id: id_optional
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          optional: 1
+          provider: views
+      filters:
+        id_optional:
+          field: id_optional
+          id: id_optional
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          optional: 1
+          provider: views
+      arguments:
+        id_optional:
+          field: id_optional
+          id: id_optional
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          optional: 1
+          provider: views
+      sorts:
+        id_optional:
+          field: id_optional
+          id: id_optional
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          order: ASC
+          optional: 1
+          provider: views
+      relationships:
+        id_optional:
+          field: id_optional
+          id: id_optional
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          optional: 1
+          provider: views
+      header:
+        id_optional:
+          field: id_optional
+          id: id_optional
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          optional: 1
+          provider: views
+      footer:
+        id_optional:
+          field: id_optional
+          id: id_optional
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          optional: 1
+          provider: views
+      empty:
+        id_optional:
+          field: id_optional
+          id: id_optional
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+          optional: 1
+          provider: views
+      pager:
+        options:
+          offset: '0'
+        type: none
+      pager_options: {  }
+    display_plugin: default
+    display_title: Master
+    id: default
+    position: '0'
+label: 'Test view'
+id: test_view_optional
+tag: ''
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php
index 2be9fbccf05677a38b7e4273e6ea0227347f2651..26ad72356edc1abad7af93e64ab2a17ad2900e1c 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Form/Ajax/ConfigItem.php
@@ -102,11 +102,12 @@ public function buildForm(array $form, array &$form_state) {
 
           // If this relationship is valid for this type, add it to the list.
           $data = Views::viewsData()->get($relationship['table']);
-          $base = $data[$relationship['field']]['relationship']['base'];
-          $base_fields = Views::viewsDataHelper()->fetchFields($base, $form_state['type'], $executable->display_handler->useGroupBy());
-          if (isset($base_fields[$item['table'] . '.' . $item['field']])) {
-            $relationship_handler->init($executable, $executable->display_handler, $relationship);
-            $relationship_options[$relationship['id']] = $relationship_handler->adminLabel();
+          if (isset($data[$relationship['field']]['relationship']['base']) && $base = $data[$relationship['field']]['relationship']['base']) {
+            $base_fields = Views::viewsDataHelper()->fetchFields($base, $form_state['type'], $executable->display_handler->useGroupBy());
+            if (isset($base_fields[$item['table'] . '.' . $item['field']])) {
+              $relationship_handler->init($executable, $executable->display_handler, $relationship);
+              $relationship_options[$relationship['id']] = $relationship_handler->adminLabel();
+            }
           }
         }
 
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Tests/HandlerTest.php b/core/modules/views_ui/lib/Drupal/views_ui/Tests/HandlerTest.php
index 79b02bf3a4c3c01d7d9e1a061f7fb50e8600d666..3be789651b0865aff2d7e354273ffc6d83222025 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/Tests/HandlerTest.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Tests/HandlerTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views_ui\Tests;
 
+use Drupal\Component\Utility\String;
 use Drupal\views\ViewExecutable;
 
 /**
@@ -21,7 +22,7 @@ class HandlerTest extends UITestBase {
    *
    * @var array
    */
-  public static $testViews = array('test_view_empty');
+  public static $testViews = array('test_view_empty', 'test_view_broken', 'test_view_optional');
 
   public static function getInfo() {
     return array(
@@ -143,4 +144,72 @@ public function testUICRUD() {
     $this->assertTrue(isset($display['display_options'][$type_info['plural']][$id]), 'Ensure the field was added to the view itself.');
   }
 
+  /**
+   * Tests broken handlers.
+   */
+  public function testBrokenHandlers() {
+    $handler_types = ViewExecutable::viewsHandlerTypes();
+    foreach ($handler_types as $type => $type_info) {
+      $this->drupalGet('admin/structure/views/view/test_view_broken/edit');
+
+      $href = "admin/structure/views/nojs/config-item/test_view_broken/default/$type/id_broken";
+
+      $result = $this->xpath('//a[contains(@href, :href)]', array(':href' => $href));
+      $this->assertEqual(count($result), 1, String::format('Handler (%type) edit link found.', array('%type' => $type)));
+
+      $text = t('Broken/missing handler (Module: @module) …', array('@module' => 'views'));
+
+      $this->assertIdentical((string) $result[0], $text, 'Ensure the broken handler text was found.');
+
+      $this->drupalGet($href);
+      $result = $this->xpath('//h1');
+      $this->assertTrue(strpos((string) $result[0], $text) !== FALSE, 'Ensure the broken handler text was found.');
+
+      $description_args = array(
+        '@module' => 'views',
+        '@table' => 'views_test_data',
+        '@field' => 'id_broken',
+      );
+
+      foreach ($description_args as $token => $value) {
+        $this->assertNoText($token, String::format('Raw @token token placeholder not found.', array('@token' => $token)));
+        $this->assertText($value, String::format('Replaced @token value found.', array('@token' => $token)));
+      }
+    }
+  }
+
+  /**
+   * Tests optional handlers.
+   */
+  public function testOptionalHandlers() {
+    $handler_types = ViewExecutable::viewsHandlerTypes();
+    foreach ($handler_types as $type => $type_info) {
+      $this->drupalGet('admin/structure/views/view/test_view_optional/edit');
+
+      $href = "admin/structure/views/nojs/config-item/test_view_optional/default/$type/id_optional";
+
+      $result = $this->xpath('//a[contains(@href, :href)]', array(':href' => $href));
+      $this->assertEqual(count($result), 1, String::format('Handler (%type) edit link found.', array('%type' => $type)));
+
+      $text = t('Optional handler is missing (Module: @module) …', array('@module' => 'views'));
+
+      $this->assertIdentical((string) $result[0], $text, 'Ensure the optional handler link text was found.');
+
+      $this->drupalGet($href);
+      $result = $this->xpath('//h1');
+      $this->assertTrue(strpos((string) $result[0], $text) !== FALSE, 'Ensure the optional handler title was found.');
+
+      $description_args = array(
+        '@module' => 'views',
+        '@table' => 'views_test_data',
+        '@field' => 'id_optional',
+      );
+
+      foreach ($description_args as $token => $value) {
+        $this->assertNoText($token, String::format('Raw @token token placeholder not found.', array('@token' => $token)));
+        $this->assertText($value, String::format('Replaced @token value found.', array('@token' => $token)));
+      }
+    }
+  }
+
 }
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
index f926d8da9d1714eda8045055f3766820cd49112e..2d81547ea81c900d3e9e01b3c1ab2def65b15e9b 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
@@ -1004,9 +1004,9 @@ public function getFormBucket(ViewUI $view, $type, $display) {
       $build['fields'][$id]['#theme'] = 'views_ui_display_tab_setting';
 
       $handler = $executable->display_handler->getHandler($type, $id);
-      if (empty($handler)) {
+      if ($handler->broken()) {
         $build['fields'][$id]['#class'][] = 'broken';
-        $field_name = $this->t('Broken/missing handler: @table > @field', array('@table' => $field['table'], '@field' => $field['field']));
+        $field_name = $handler->adminLabel();
         $build['fields'][$id]['#link'] = l($field_name, "admin/structure/views/nojs/config-item/{$view->id()}/{$display['id']}/$type/$id", array('attributes' => array('class' => array('views-ajax-link')), 'html' => TRUE));
         continue;
       }