diff --git a/core/modules/block_content/src/BlockContentViewsData.php b/core/modules/block_content/src/BlockContentViewsData.php
index 3cd4a39..09d49b7 100644
--- a/core/modules/block_content/src/BlockContentViewsData.php
+++ b/core/modules/block_content/src/BlockContentViewsData.php
@@ -28,18 +28,6 @@ public function getViewsData() {
 
     $data['block_content_field_data']['type']['field']['id'] = 'field';
 
-    // @todo Figure out the way to integrate this automatic in
-    //   content_translation https://www.drupal.org/node/2410261.
-    if ($this->moduleHandler->moduleExists('content_translation')) {
-      $data['block_content']['translation_link'] = array(
-        'title' => $this->t('Translation link'),
-        'help' => $this->t('Provide a link to the translations overview for custom blocks.'),
-        'field' => array(
-          'id' => 'content_translation_link',
-        ),
-      );
-    }
-
     // Advertise this table as a possible base table.
     $data['block_content_revision']['table']['base']['help'] = $this->t('Block Content revision is a history of changes to block content.');
     $data['block_content_revision']['table']['base']['defaults']['title'] = 'info';
diff --git a/core/modules/comment/config/schema/comment.views.schema.yml b/core/modules/comment/config/schema/comment.views.schema.yml
index ed3f70b..f8783b1 100644
--- a/core/modules/comment/config/schema/comment.views.schema.yml
+++ b/core/modules/comment/config/schema/comment.views.schema.yml
@@ -35,18 +35,6 @@ views.field.comment_link_approve:
   type: views.field.comment_link
   label: 'Comment approve link'
 
-views.field.comment_link_delete:
-  type: views.field.comment_link
-  label: 'Comment delete link'
-
-views.field.comment_link_edit:
-  type: views.field.comment_link
-  label: 'Comment edit link'
-  mapping:
-    destination:
-      type: boolean
-      label: 'Use destination'
-
 views.field.comment_link_reply:
   type: views.field.comment_link
   label: 'Comment reply link'
diff --git a/core/modules/comment/src/CommentViewsData.php b/core/modules/comment/src/CommentViewsData.php
index e853a58..c70f77f 100644
--- a/core/modules/comment/src/CommentViewsData.php
+++ b/core/modules/comment/src/CommentViewsData.php
@@ -102,30 +102,6 @@ public function getViewsData() {
     $data['comment_field_data']['status']['filter']['label'] = t('Approved comment status');
     $data['comment_field_data']['status']['filter']['type'] = 'yes-no';
 
-    $data['comment']['view_comment'] = array(
-      'field' => array(
-        'title' => t('Link to comment'),
-        'help' => t('Provide a simple link to view the comment.'),
-        'id' => 'comment_link',
-      ),
-    );
-
-    $data['comment']['edit_comment'] = array(
-      'field' => array(
-        'title' => t('Link to edit comment'),
-        'help' => t('Provide a simple link to edit the comment.'),
-        'id' => 'comment_link_edit',
-      ),
-    );
-
-    $data['comment']['delete_comment'] = array(
-      'field' => array(
-        'title' => t('Link to delete comment'),
-        'help' => t('Provide a simple link to delete the comment.'),
-        'id' => 'comment_link_delete',
-      ),
-    );
-
     $data['comment']['approve_comment'] = array(
       'field' => array(
         'title' => t('Link to approve comment'),
@@ -195,16 +171,6 @@ public function getViewsData() {
     $data['comment_field_data']['pid']['relationship']['help'] = t('The parent comment');
     $data['comment_field_data']['pid']['relationship']['label'] = t('parent');
 
-    if (\Drupal::moduleHandler()->moduleExists('content_translation')) {
-      $data['comment']['translation_link'] = array(
-        'title' => t('Translation link'),
-        'help' => t('Provide a link to the translations overview for comments.'),
-        'field' => array(
-          'id' => 'content_translation_link',
-        ),
-      );
-    }
-
     // Define the base group of this table. Fields that don't have a group defined
     // will go into this field by default.
     $data['comment_entity_statistics']['table']['group']  = t('Comment Statistics');
diff --git a/core/modules/comment/src/Plugin/views/field/LinkDelete.php b/core/modules/comment/src/Plugin/views/field/LinkDelete.php
deleted file mode 100644
index 5ede03f..0000000
--- a/core/modules/comment/src/Plugin/views/field/LinkDelete.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\comment\Plugin\views\field\LinkDelete.
- */
-
-namespace Drupal\comment\Plugin\views\field;
-
-use Drupal\Core\Session\AccountInterface;
-use Drupal\views\ResultRow;
-
-/**
- * Field handler to present a link to delete a comment.
- *
- * @ingroup views_field_handlers
- *
- * @ViewsField("comment_link_delete")
- */
-class LinkDelete extends Link {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function access(AccountInterface $account) {
-    //needs permission to administer comments in general
-    return $account->hasPermission('administer comments');
-  }
-
-  /**
-   * Prepares the link for deleting the comment.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $data
-   *   The comment entity.
-   * @param \Drupal\views\ResultRow $values
-   *   The values retrieved from a single row of a view's query result.
-   *
-   * @return string
-   *   Returns a string for the link text.
-   */
-  protected function renderLink($data, ResultRow $values) {
-    $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Delete');
-    $comment = $this->getEntity($values);
-
-    $this->options['alter']['make_link'] = TRUE;
-    $this->options['alter']['url'] = $comment->urlInfo('delete-form');
-    $this->options['alter']['query'] = $this->getDestinationArray();
-
-    return $text;
-  }
-
-}
diff --git a/core/modules/comment/src/Plugin/views/field/LinkEdit.php b/core/modules/comment/src/Plugin/views/field/LinkEdit.php
deleted file mode 100644
index 7ae0693..0000000
--- a/core/modules/comment/src/Plugin/views/field/LinkEdit.php
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\comment\Plugin\views\field\LinkEdit.
- */
-
-namespace Drupal\comment\Plugin\views\field;
-
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\views\ResultRow;
-
-/**
- * Field handler to present a link to edit a comment.
- *
- * @ingroup views_field_handlers
- *
- * @ViewsField("comment_link_edit")
- */
-class LinkEdit extends Link {
-
-  protected function defineOptions() {
-    $options = parent::defineOptions();
-    $options['destination'] = array('default' => FALSE);
-
-    return $options;
-  }
-
-  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
-    parent::buildOptionsForm($form, $form_state);
-
-    $form['destination'] = array(
-      '#type' => 'checkbox',
-      '#title' => $this->t('Use destination'),
-      '#description' => $this->t('Add destination to the link'),
-      '#default_value' => $this->options['destination'],
-    );
-  }
-
-  /**
-   * Prepare the link for editing the comment.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $data
-   *   The comment entity.
-   * @param \Drupal\views\ResultRow $values
-   *   The values retrieved from a single row of a view's query result.
-   *
-   * @return string
-   *   Returns a string for the link text.
-   */
-  protected function renderLink($data, ResultRow $values) {
-    parent::renderLink($data, $values);
-    // Ensure user has access to edit this comment.
-    $comment = $this->getValue($values);
-    if (!$comment->access('update')) {
-      return;
-    }
-
-    $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Edit');
-    unset($this->options['alter']['fragment']);
-
-    if (!empty($this->options['destination'])) {
-      $this->options['alter']['query'] = $this->getDestinationArray();
-    }
-
-    $this->options['alter']['url'] = $comment->urlInfo('edit-form');
-
-    return $text;
-  }
-
-}
diff --git a/core/modules/content_translation/src/Plugin/views/field/TranslationLink.php b/core/modules/content_translation/src/Plugin/views/field/TranslationLink.php
index a084dfe..654520d 100644
--- a/core/modules/content_translation/src/Plugin/views/field/TranslationLink.php
+++ b/core/modules/content_translation/src/Plugin/views/field/TranslationLink.php
@@ -7,8 +7,7 @@
 
 namespace Drupal\content_translation\Plugin\views\field;
 
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\views\Plugin\views\field\FieldPluginBase;
+use Drupal\views\Plugin\views\field\EntityLink;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\views\ResultRow;
 
@@ -19,47 +18,11 @@
  *
  * @ViewsField("content_translation_link")
  */
-class TranslationLink extends FieldPluginBase {
+class TranslationLink extends EntityLink {
 
   /**
    * {@inheritdoc}
    */
-  protected function defineOptions() {
-    $options = parent::defineOptions();
-    $options['text'] = array('default' => '');
-    return $options;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
-    $form['text'] = array(
-      '#type' => 'textfield',
-      '#title' => $this->t('Text to display'),
-      '#default_value' => $this->options['text'],
-    );
-    parent::buildOptionsForm($form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function render(ResultRow $values) {
-    return $this->renderLink($this->getEntity($values), $values);
-  }
-
-  /**
-   * Alters the field to render a link.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity being rendered.
-   * @param \Drupal\views\ResultRow $values
-   *   The current row of the views result.
-   *
-   * @return string
-   *   The actual rendered text (without the link) of this field.
-   */
   protected function renderLink(EntityInterface $entity, ResultRow $values) {
     if (content_translation_translate_access($entity)->isAllowed()) {
       $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Translate');
@@ -71,17 +34,4 @@ protected function renderLink(EntityInterface $entity, ResultRow $values) {
     }
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function query() {
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function clickSortable() {
-    return FALSE;
-  }
-
 }
diff --git a/core/modules/node/config/optional/views.view.content_recent.yml b/core/modules/node/config/optional/views.view.content_recent.yml
index 1ad0161..500e1fa 100644
--- a/core/modules/node/config/optional/views.view.content_recent.yml
+++ b/core/modules/node/config/optional/views.view.content_recent.yml
@@ -239,7 +239,7 @@ display:
           hide_alter_empty: true
           text: Edit
           entity_type: node
-          plugin_id: node_link_edit
+          plugin_id: entity_link_edit
         delete_node:
           id: delete_node
           table: node
@@ -290,7 +290,7 @@ display:
           hide_alter_empty: true
           text: Delete
           entity_type: node
-          plugin_id: node_link_delete
+          plugin_id: entity_link_delete
       filters:
         status_extra:
           id: status_extra
diff --git a/core/modules/node/config/schema/node.views.schema.yml b/core/modules/node/config/schema/node.views.schema.yml
index b1e8e73..864e9ee 100644
--- a/core/modules/node/config/schema/node.views.schema.yml
+++ b/core/modules/node/config/schema/node.views.schema.yml
@@ -94,37 +94,13 @@ views.argument_validator.node:
       label: 'Filter value format'
 
 views.field.node:
-  type: views_field
+  type: views.field.entity_link
   label: 'Node'
   mapping:
     link_to_node:
       type: boolean
       label: 'Link this field to the original piece of content'
 
-views.field.node_link:
-  type: views_field
-  label: 'Node link'
-  mapping:
-    text:
-      type: label
-      label: 'Text to display'
-
-views.field.node_link_delete:
-  type: views_field
-  label: 'Node delete link'
-  mapping:
-    text:
-      type: label
-      label: 'Text to display'
-
-views.field.node_link_edit:
-  type: views_field
-  label: 'Node edit link'
-  mapping:
-    text:
-      type: label
-      label: 'Text to display'
-
 views.field.node_bulk_form:
   type: views_field_bulk_form
   label: 'Node bulk form'
diff --git a/core/modules/node/src/NodeViewsData.php b/core/modules/node/src/NodeViewsData.php
index aecaec2..fb84daa 100644
--- a/core/modules/node/src/NodeViewsData.php
+++ b/core/modules/node/src/NodeViewsData.php
@@ -61,40 +61,6 @@ public function getViewsData() {
     $data['node_field_data']['sticky']['filter']['type'] = 'yes-no';
     $data['node_field_data']['sticky']['sort']['help'] = t('Whether or not the content is sticky. To list sticky content first, set this to descending.');
 
-    if (\Drupal::moduleHandler()->moduleExists('content_translation')) {
-      $data['node']['translation_link'] = array(
-        'title' => t('Translation link'),
-        'help' => t('Provide a link to the translations overview for nodes.'),
-        'field' => array(
-          'id' => 'content_translation_link',
-        ),
-      );
-    }
-
-    $data['node']['view_node'] = array(
-      'field' => array(
-        'title' => t('Link to content'),
-        'help' => t('Provide a simple link to the content.'),
-        'id' => 'node_link',
-      ),
-    );
-
-    $data['node']['edit_node'] = array(
-      'field' => array(
-        'title' => t('Link to edit content'),
-        'help' => t('Provide a simple link to edit the content.'),
-        'id' => 'node_link_edit',
-      ),
-    );
-
-    $data['node']['delete_node'] = array(
-      'field' => array(
-        'title' => t('Link to delete content'),
-        'help' => t('Provide a simple link to delete the content.'),
-        'id' => 'node_link_delete',
-      ),
-    );
-
     $data['node']['path'] = array(
       'field' => array(
         'title' => t('Path'),
diff --git a/core/modules/node/src/Plugin/views/field/Node.php b/core/modules/node/src/Plugin/views/field/Node.php
index 43077e2..ba328b3 100644
--- a/core/modules/node/src/Plugin/views/field/Node.php
+++ b/core/modules/node/src/Plugin/views/field/Node.php
@@ -37,9 +37,6 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
     }
   }
 
-  /**
-   * {@inheritdoc}
-   */
   protected function defineOptions() {
     $options = parent::defineOptions();
     $options['link_to_node'] = array('default' => isset($this->definition['link_to_node default']) ? $this->definition['link_to_node default'] : FALSE);
diff --git a/core/modules/taxonomy/src/TermViewsData.php b/core/modules/taxonomy/src/TermViewsData.php
index 1d3ba6f..aa1d0c0 100644
--- a/core/modules/taxonomy/src/TermViewsData.php
+++ b/core/modules/taxonomy/src/TermViewsData.php
@@ -84,16 +84,6 @@ public function getViewsData() {
       ),
     );
 
-    if (\Drupal::moduleHandler()->moduleExists('content_translation')) {
-      $data['taxonomy_term_data']['translation_link'] = array(
-        'title' => t('Translation link'),
-        'help' => t('Provide a link to the translations overview for taxonomy terms.'),
-        'field' => array(
-          'id' => 'content_translation_link',
-        ),
-      );
-    }
-
     $data['taxonomy_term_field_data']['name']['field']['id'] = 'term_name';
     $data['taxonomy_term_field_data']['name']['argument']['many to one'] = TRUE;
     $data['taxonomy_term_field_data']['name']['argument']['empty field name'] = t('Uncategorized');
diff --git a/core/modules/user/src/Plugin/views/field/LinkEdit.php b/core/modules/user/src/Plugin/views/field/LinkEdit.php
deleted file mode 100644
index 23a4f5a..0000000
--- a/core/modules/user/src/Plugin/views/field/LinkEdit.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\user\Plugin\views\field\LinkEdit.
- */
-
-namespace Drupal\user\Plugin\views\field;
-
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\views\ResultRow;
-
-/**
- * Field handler to present a link to user edit.
- *
- * @ingroup views_field_handlers
- *
- * @ViewsField("user_link_edit")
- */
-class LinkEdit extends Link {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function renderLink(EntityInterface $entity, ResultRow $values) {
-    if ($entity && $entity->access('update')) {
-      $this->options['alter']['make_link'] = TRUE;
-
-      $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Edit');
-
-      $this->options['alter']['url'] = $entity->urlInfo('edit-form', ['query' => ['destination' => $this->getDestinationArray()]]);
-
-      return $text;
-    }
-  }
-
-}
diff --git a/core/modules/user/src/UserViewsData.php b/core/modules/user/src/UserViewsData.php
index edbdb99..a018e78 100644
--- a/core/modules/user/src/UserViewsData.php
+++ b/core/modules/user/src/UserViewsData.php
@@ -216,25 +216,6 @@ public function getViewsData() {
       ),
     );
 
-    if (\Drupal::moduleHandler()->moduleExists('content_translation')) {
-      $data['users']['translation_link'] = array(
-        'title' => t('Translation link'),
-        'help' => t('Provide a link to the translations overview for users.'),
-        'field' => array(
-          'id' => 'content_translation_link',
-        ),
-      );
-    }
-
-    $data['users']['edit_node'] = array(
-      'field' => array(
-        'title' => t('Link to edit user'),
-        'help' => t('Provide a simple link to edit the user.'),
-        'id' => 'user_link_edit',
-        'click sortable' => FALSE,
-      ),
-    );
-
     $data['users']['cancel_node'] = array(
       'field' => array(
         'title' => t('Link to cancel user'),
diff --git a/core/modules/views/config/schema/views.field.schema.yml b/core/modules/views/config/schema/views.field.schema.yml
index de8ffcb..6c310a2 100644
--- a/core/modules/views/config/schema/views.field.schema.yml
+++ b/core/modules/views/config/schema/views.field.schema.yml
@@ -171,11 +171,22 @@ views.field.url:
 views.field.language:
   type: views_field
   label: 'Language'
+
+views.field.entity_link:
+  type: views_field
+  label: 'Entity link'
   mapping:
     native_language:
       type: boolean
       label: 'Display in native language'
+    text:
+      type: label
+      label: 'Text to display'
 
+views.field.entity_link_delete:
+  type: views.field.entity_link
+  label: 'Entity delete link'
+  mapping:
 views.field.bulk_form:
   type: views_field_bulk_form
   label: 'Bulk form'
@@ -183,8 +194,12 @@ views.field.bulk_form:
 views.field.field:
   type: views_field
   label: 'Views entity field handler'
+views.field.entity_link_edit:
+  type: views.field.entity_link
+  label: 'Entity edit link'
   mapping:
     click_sort_column:
+    text:
       type: string
       label: 'Column used for click sorting'
     type:
@@ -223,6 +238,7 @@ views.field.field:
     separator:
       type: label
       label: 'Separator'
+      label: 'Text to display'
     field_api_classes:
       type: boolean
       label: 'Use field template'
diff --git a/core/modules/views/src/EntityViewsData.php b/core/modules/views/src/EntityViewsData.php
index a22fd02..9cbb31c 100644
--- a/core/modules/views/src/EntityViewsData.php
+++ b/core/modules/views/src/EntityViewsData.php
@@ -203,6 +203,8 @@ public function getViewsData() {
       }
     }
 
+    $this->addEntityLinks($data[$base_table]);
+
     // Load all typed data definitions of all fields. This should cover each of
     // the entity base, revision, data tables.
     $field_definitions = $this->entityManager->getBaseFieldDefinitions($this->entityType->id());
@@ -230,6 +232,53 @@ public function getViewsData() {
   }
 
   /**
+   * Sets the entity links in case corresponding link templates exist.
+   *
+   * @param array $data
+   *   The views data of the base table.
+   */
+  protected function addEntityLinks(array &$data) {
+    $entity_type_id = $this->entityType->id();
+    $t_arguments = ['@entity_type_label' => $this->entityType->getLabel()];
+    if ($this->entityType->hasLinkTemplate('canonical')) {
+      $data['view_' . $entity_type_id] = [
+        'field' => [
+          'title' => $this->t('Link to @entity_type_label', $t_arguments),
+          'help' => $this->t('Provide a view link to the @entity_type_label.', $t_arguments),
+          'id' => 'entity_link',
+        ],
+      ];
+    }
+    if ($this->entityType->hasLinkTemplate('edit-form')) {
+      $data['edit_' . $entity_type_id] = [
+        'field' => [
+          'title' => $this->t('Link to edit @entity_type_label', $t_arguments),
+          'help' => $this->t('Provide an edit link to the @entity_type_label.', $t_arguments),
+          'id' => 'entity_link_edit',
+        ],
+      ];
+    }
+    if ($this->entityType->hasLinkTemplate('delete-form')) {
+      $data['delete_' . $entity_type_id] = [
+        'field' => [
+          'title' => $this->t('Link to delete @entity_type_label', $t_arguments),
+          'help' => $this->t('Provide a delete link to the @entity_type_label.', $t_arguments),
+          'id' => 'entity_link_delete',
+        ],
+      ];
+    }
+    if ($this->entityType->hasLinkTemplate('drupal:content-translation-overview')) {
+      $data['translate_' . $entity_type_id] = [
+        'field' => [
+          'title' => $this->t('Link to translate @entity_type_label', $t_arguments),
+          'help' => $this->t('Provide a translate link to the @entity_type_label.', $t_arguments),
+          'id' => 'content_translation_link',
+        ],
+      ];
+    }
+  }
+
+  /**
    * Puts the views data for a single field onto the views data.
    *
    * @param string $table
diff --git a/core/modules/views/src/Plugin/views/field/EntityLink.php b/core/modules/views/src/Plugin/views/field/EntityLink.php
new file mode 100644
index 0000000..d677cbd
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/field/EntityLink.php
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Plugin\views\field\EntityLink.
+ */
+
+namespace Drupal\views\Plugin\views\field;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+
+/**
+ * Field handler to present a link to the entity_link.
+ *
+ * @ingroup views_field_handlers
+ *
+ * @ViewsField("entity_link")
+ */
+class EntityLink extends FieldPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
+    parent::init($view, $display, $options);
+
+    // @FIXME
+    // $this->additional_fields['langcode'] = ['table' => 'node_field_data', 'field' => 'langcode'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function usesGroupBy() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function defineOptions() {
+    $options = parent::defineOptions();
+    $options['text'] = ['default' => '', 'translatable' => TRUE];
+    return $options;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
+    $form['text'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Text to display'),
+      '#default_value' => $this->options['text'],
+    ];
+    parent::buildOptionsForm($form, $form_state);
+
+    // The path is set by renderLink function so don't allow to set it.
+    $form['alter']['path'] = ['#access' => FALSE];
+    $form['alter']['external'] = ['#access' => FALSE];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    $this->addAdditionalFields();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render(ResultRow $values) {
+    if ($entity = $this->getEntity($values)) {
+      return $this->renderLink($entity, $values);
+    }
+  }
+
+  /**
+   * Prepares the link to view a entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The node entity this field belongs to.
+   * @param \Drupal\views\ResultRow $values
+   *   The values retrieved from the view's result set.
+   *
+   * @return string
+   *   Returns a string for the link text.
+   */
+  protected function renderLink($entity, ResultRow $values) {
+    if ($entity->access('view')) {
+      $this->options['alter']['make_link'] = TRUE;
+      $this->options['alter']['path'] = $entity->getSystemPath();
+
+      $this->addLangcode($values);
+
+      $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('view');
+      return $text;
+    }
+  }
+
+  /**
+   * @param \Drupal\views\ResultRow $values
+   */
+  protected function addLangcode(ResultRow $values) {
+    if (isset($this->aliases['langcode'])) {
+      $languages = language_list();
+      $langcode = $this->getValue($values, 'langcode');
+      if (isset($languages[$langcode])) {
+        $this->options['alter']['language'] = $languages[$langcode];
+      }
+      else {
+        unset($this->options['alter']['language']);
+      }
+    }
+  }
+}
diff --git a/core/modules/views/src/Plugin/views/field/EntityLinkDelete.php b/core/modules/views/src/Plugin/views/field/EntityLinkDelete.php
new file mode 100644
index 0000000..8245714
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/field/EntityLinkDelete.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Plugin\views\field\EntityLinkDelete.
+ */
+
+namespace Drupal\views\Plugin\views\field;
+
+use Drupal\views\ResultRow;
+
+/**
+ * Field handler to present a link to delete an entity.
+ *
+ * @ingroup views_field_handlers
+ *
+ * @ViewsField("entity_link_delete")
+ */
+class EntityLinkDelete extends EntityLink {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function renderLink($entity, ResultRow $values) {
+    // Ensure user has access to delete this node.
+    if ($entity && $entity->access('delete')) {
+      $this->options['alter']['make_link'] = TRUE;
+      $this->options['alter']['path'] = $entity->getSystemPath('delete-form');
+      $this->options['alter']['query'] = drupal_get_destination();
+
+      $this->addLangcode($values);
+
+      $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('delete');
+      return $text;
+    }
+  }
+
+}
diff --git a/core/modules/views/src/Plugin/views/field/EntityLinkEdit.php b/core/modules/views/src/Plugin/views/field/EntityLinkEdit.php
new file mode 100644
index 0000000..67b0bf2
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/field/EntityLinkEdit.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Plugin\views\field\EntityLinkEdit.
+ */
+
+namespace Drupal\views\Plugin\views\field;
+
+use Drupal\views\ResultRow;
+
+/**
+ * Field handler to present a link to edit an entity.
+ *
+ * @ingroup views_field_handlers
+ *
+ * @ViewsField("entity_link_edit")
+ */
+class EntityLinkEdit extends EntityLink {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function renderLink($entity, ResultRow $values) {
+    // Ensure user has access to delete this node.
+    if ($entity && $entity->access('update')) {
+      $this->options['alter']['make_link'] = TRUE;
+      $this->options['alter']['path'] = $entity->getSystemPath('edit-form');
+      $this->options['alter']['query'] = drupal_get_destination();
+
+      $this->addLangcode($values);
+
+      $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('edit');
+      return $text;
+    }
+  }
+
+}
diff --git a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
index 56d1596..e8e49d6 100644
--- a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
+++ b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
@@ -712,6 +712,35 @@ protected function assertField($data, $field_name) {
   }
 
   /**
+   * Tests add link types.
+   */
+  public function testEntityLinks() {
+    $this->baseEntityType->setLinkTemplate('canonical', '/entity_test/{entity_test}');
+    $this->baseEntityType->setLinkTemplate('edit-form', '/entity_test/{entity_test}/edit');
+    $this->baseEntityType->setLinkTemplate('delete-form', '/entity_test/{entity_test}/delete');
+    $this->baseEntityType->setLinkTemplate('drupal:content-translation-overview', '/entity_test/{entity_test}/translate');
+
+    $data = $this->viewsData->getViewsData();
+    $this->assertEquals('entity_link', $data['entity_test']['view_entity_test']['field']['id']);
+    $this->assertEquals('entity_link_edit', $data['entity_test']['edit_entity_test']['field']['id']);
+    $this->assertEquals('entity_link_delete', $data['entity_test']['delete_entity_test']['field']['id']);
+    $this->assertEquals('content_translation_link', $data['entity_test']['translate_entity_test']['field']['id']);
+  }
+
+  /**
+   * Tests additional edit links.
+   */
+  public function testEntityLinksJustEditForm() {
+    $this->baseEntityType->setLinkTemplate('edit-form', '/entity_test/{entity_test}/edit');
+
+    $data = $this->viewsData->getViewsData();
+    $this->assertFalse(isset($data['entity_test']['view_entity_test']));
+    $this->assertFalse(isset($data['entity_test']['delete_entity_test']));
+
+    $this->assertEquals('entity_link_edit', $data['entity_test']['edit_entity_test']['field']['id']);
+  }
+
+  /**
    * Tests views data for a string field.
    *
    * @param $data
