diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml
index 6acd1e6..69e1dd9 100644
--- a/core/config/schema/core.entity.schema.yml
+++ b/core/config/schema/core.entity.schema.yml
@@ -225,6 +225,13 @@ field.widget.settings.checkbox:
       type: boolean
       label: 'Use field label instead of the "On value" as label'
 
+field.formatter.settings.string:
+  type: mapping
+  mapping:
+    link_to_entity:
+      type: boolean
+      label: 'Link to the entity'
+
 field.formatter.settings.number_decimal:
   type: mapping
   label: 'Number decimal display format settings'
diff --git a/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php b/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php
index f992081..e9dbf72 100644
--- a/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php
+++ b/core/lib/Drupal/Core/Entity/Sql/DefaultTableMapping.php
@@ -323,7 +323,15 @@ protected function generateFieldTableName(FieldStorageDefinitionInterface $stora
    * {@inheritdoc}
    */
   public function getFieldColumnName(FieldStorageDefinitionInterface $storage_definition, $column) {
-    return in_array($column, $this->getReservedColumns()) ? $column : $storage_definition->getName() . '_' . $column;
+    if (in_array($column, $this->getReservedColumns())) {
+      return $column;
+    }
+
+    if ($storage_definition->isBaseField() && count($storage_definition->getColumns()) === 1) {
+      return $storage_definition->getName();
+    }
+
+    return $storage_definition->getName() . '_' . $column;
   }
 
 }
diff --git a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
index a96bdd4..93f65d3 100644
--- a/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
+++ b/core/lib/Drupal/Core/Field/BaseFieldDefinition.php
@@ -92,7 +92,6 @@ public static function createFromFieldStorageDefinition(FieldStorageDefinitionIn
       ->setName($definition->getName())
       ->setProvider($definition->getProvider())
       ->setQueryable($definition->isQueryable())
-      ->setRequired($definition->isRequired())
       ->setRevisionable($definition->isRevisionable())
       ->setSettings($definition->getSettings())
       ->setTargetEntityTypeId($definition->getTargetEntityTypeId())
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/StringFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/StringFormatter.php
index 544ae46..521a62a 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/StringFormatter.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/StringFormatter.php
@@ -8,8 +8,13 @@
 namespace Drupal\Core\Field\Plugin\Field\FieldFormatter;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Plugin implementation of the 'string' formatter.
@@ -27,7 +32,89 @@
  *   }
  * )
  */
-class StringFormatter extends FormatterBase {
+class StringFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * Constructs a StringFormatter instance.
+   *
+   * @param string $plugin_id
+   *   The plugin_id for the formatter.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
+   *   The definition of the field to which the formatter is associated.
+   * @param array $settings
+   *   The formatter settings.
+   * @param string $label
+   *   The formatter label display setting.
+   * @param string $view_mode
+   *   The view mode.
+   * @param array $third_party_settings
+   *   Any third party settings settings.
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   */
+  public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, EntityManagerInterface $entity_manager) {
+    parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
+
+    $this->entityManager = $entity_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $plugin_id,
+      $plugin_definition,
+      $configuration['field_definition'],
+      $configuration['settings'],
+      $configuration['label'],
+      $configuration['view_mode'],
+      $configuration['third_party_settings'],
+      $container->get('entity.manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function defaultSettings() {
+    $options = parent::defaultSettings();
+
+    $options['link_to_entity'] = FALSE;
+    return $options;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $form = parent::settingsForm($form, $form_state);
+
+    if ($this->fieldDefinition->getType() === 'string') {
+      $entity_type = $this->entityManager->getDefinition($this->fieldDefinition->getTargetEntityTypeId());
+      $form['link_to_entity'] = [
+        '#type' => 'checkbox',
+        '#title' => $this->t('Link to the @entity_label', ['@entity_label' => $entity_type->getLabel()]),
+        '#default_value' => $this->getSetting('link_to_entity'),
+      ];
+    }
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsSummary() {
+    $build = [];
+    if ($this->fieldDefinition->getType() === 'string' && $this->getSetting('link_to_entity')) {
+      $entity_type = $this->entityManager->getDefinition($this->fieldDefinition->getTargetEntityTypeId());
+      $build['#markup'] = $this->t('Linked to the @entity_label', ['@entity_label' => $entity_type->getLabel()]);
+    }
+    return $build;
+  }
 
   /**
    * {@inheritdoc}
@@ -35,10 +122,27 @@ class StringFormatter extends FormatterBase {
   public function viewElements(FieldItemListInterface $items) {
     $elements = array();
 
+    $url = NULL;
+    // Add support to link to the entity itself.
+    if ($this->fieldDefinition->getType() === 'string' && $this->getSetting('link_to_entity') && ($entity = $items->getEntity()) && $entity->hasLinkTemplate('canonical')) {
+      $url = $entity->urlInfo();
+    }
+
     foreach ($items as $delta => $item) {
       // The text value has no text format assigned to it, so the user input
       // should equal the output, including newlines.
-      $elements[$delta] = array('#markup' => nl2br(String::checkPlain($item->value)));
+      $string = nl2br(String::checkPlain($item->value));
+
+      if ($url) {
+        $elements[$delta] = [
+          '#type' => 'link',
+          '#title' => $string,
+          '#url' => $url,
+        ];
+      }
+      else {
+        $elements[$delta] = ['#markup' => $string];
+      }
     }
 
     return $elements;
diff --git a/core/modules/field/src/Plugin/views/field/Field.php b/core/modules/field/src/Plugin/views/field/Field.php
index 95dd59e..02c5a84 100644
--- a/core/modules/field/src/Plugin/views/field/Field.php
+++ b/core/modules/field/src/Plugin/views/field/Field.php
@@ -14,12 +14,14 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Field\FieldTypePluginManagerInterface;
 use Drupal\Core\Field\FormatterPluginManager;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\field\FieldStorageConfigInterface;
 use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
@@ -112,6 +114,13 @@ class Field extends FieldPluginBase implements CacheablePluginInterface {
   protected $languageManager;
 
   /**
+   * The field type plugin manager.
+   *
+   * @var \Drupal\Core\Field\FieldTypePluginManagerInterface
+   */
+  protected $fieldTypePluginManager;
+
+  /**
    * Constructs a \Drupal\field\Plugin\views\field\Field object.
    *
    * @param array $configuration
@@ -127,11 +136,12 @@ class Field extends FieldPluginBase implements CacheablePluginInterface {
    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
    *   The language manager.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, FormatterPluginManager $formatter_plugin_manager, LanguageManagerInterface $language_manager) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, FormatterPluginManager $formatter_plugin_manager, FieldTypePluginManagerInterface $field_type_plugin_manager, LanguageManagerInterface $language_manager) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
 
     $this->entityManager = $entity_manager;
     $this->formatterPluginManager = $formatter_plugin_manager;
+    $this->fieldTypePluginManager = $field_type_plugin_manager;
     $this->languageManager = $language_manager;
   }
 
@@ -145,6 +155,7 @@ public static function create(ContainerInterface $container, array $configuratio
       $plugin_definition,
       $container->get('entity.manager'),
       $container->get('plugin.manager.field.formatter'),
+      $container->get('plugin.manager.field.field_type'),
       $container->get('language_manager')
     );
   }
@@ -170,7 +181,7 @@ protected function getFieldDefinition() {
    */
   protected function getFieldStorageConfig() {
     if (!$this->fieldStorageConfig) {
-      $field_storage_definitions = \Drupal::entityManager()->getFieldStorageDefinitions($this->definition['entity_type']);
+      $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($this->definition['entity_type']);
       $this->fieldStorageConfig = $field_storage_definitions[$this->definition['field_name']];
     }
     return $this->fieldStorageConfig;
@@ -353,8 +364,7 @@ public function clickSort($order) {
 
     $this->ensureMyTable();
     $entity_type_id = $this->definition['entity_type'];
-    $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id);
-    $field_storage = $field_storage_definitions[$this->definition['field_name']];
+    $field_storage = $this->getFieldStorage();
     /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
     $table_mapping = $this->entityManager->getStorage($entity_type_id)->getTableMapping();
     $column = $table_mapping->getFieldColumnName($field_storage, $this->options['click_sort_column']);
@@ -365,12 +375,26 @@ public function clickSort($order) {
     $this->query->addOrderBy(NULL, NULL, $order, $this->aliases[$column]);
   }
 
+  /**
+   * Gets the field storage of the used field.
+   *
+   * @return \Drupal\Core\Field\FieldStorageDefinitionInterface
+   */
+  protected function getFieldStorage() {
+    $entity_type_id = $this->definition['entity_type'];
+    $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id);
+    $field_storage = $field_storage_definitions[$this->definition['field_name']];
+    return $field_storage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   protected function defineOptions() {
     $options = parent::defineOptions();
 
-    $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($this->definition['entity_type']);
-    $field_storage = $field_storage_definitions[$this->definition['field_name']];
-    $field_type = \Drupal::service('plugin.manager.field.field_type')->getDefinition($field_storage->getType());
+    $field_storage = $this->getFieldStorage();
+    $field_type = $this->fieldTypePluginManager->getDefinition($field_storage->getType());
     $column_names = array_keys($field_storage->getColumns());
     $default_column = '';
     // Try to determine a sensible default.
@@ -389,7 +413,7 @@ protected function defineOptions() {
       'default' => $field_type['default_formatter'],
     );
     $options['settings'] = array(
-      'default' => array(),
+      'default' => isset($this->definition['default_formatter_settings']) ? $this->definition['default_formatter_settings'] : [],
     );
     $options['group_column'] = array(
       'default' => $default_column,
@@ -940,7 +964,12 @@ function field_langcode(EntityInterface $entity) {
    */
   public function calculateDependencies() {
     // Add the module providing the configured field storage as a dependency.
-    return array('config' => array($this->getFieldStorageConfig()->getConfigDependencyName()));
+
+    if (($field_storage = $this->getFieldStorageConfig()) && $field_storage instanceof FieldStorageConfigInterface) {
+      return ['config' => [$field_storage->getConfigDependencyName()]];
+    }
+
+    return [];
   }
 
   /**
diff --git a/core/modules/field/src/Tests/String/StringFormatterTest.php b/core/modules/field/src/Tests/String/StringFormatterTest.php
index 0cf3f77..bc23148 100644
--- a/core/modules/field/src/Tests/String/StringFormatterTest.php
+++ b/core/modules/field/src/Tests/String/StringFormatterTest.php
@@ -58,6 +58,8 @@ protected function setUp() {
 
     // Configure the theme system.
     $this->installConfig(array('system', 'field'));
+    $this->installSchema('system', 'router');
+    \Drupal::service('router.builder')->rebuild();
     $this->installEntitySchema('entity_test');
 
     $this->entityType = 'entity_test';
@@ -122,6 +124,23 @@ public function testStringFormatter() {
     // Verify the cache tags.
     $build = $entity->{$this->fieldName}->view();
     $this->assertTrue(!isset($build[0]['#cache']), format_string('The string formatter has no cache tags.'));
+
+    // Set the formatter to link to the entity.
+    $this->display->setComponent($this->fieldName, [
+      'type' => 'string',
+      'settings' => [
+        'link_to_entity' => TRUE,
+      ],
+    ]);
+    $this->display->save();
+
+    $value = $this->randomMachineName();
+    $entity->{$this->fieldName}->value = $value;
+    $entity->save();
+
+    $this->renderEntityFields($entity, $this->display);
+    $this->assertLink($value, 0);
+    $this->assertLinkByHref($entity->url());
   }
 
 }
diff --git a/core/modules/field/tests/src/Unit/Plugin/views/field/FieldTest.php b/core/modules/field/tests/src/Unit/Plugin/views/field/FieldTest.php
new file mode 100644
index 0000000..cfac240
--- /dev/null
+++ b/core/modules/field/tests/src/Unit/Plugin/views/field/FieldTest.php
@@ -0,0 +1,396 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\field\Unit\Plugin\views\field\FieldTest.
+ */
+
+namespace Drupal\Tests\field\Unit\Plugin\views\field;
+
+use Drupal\field\Plugin\views\field\Field;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\views\Plugin\views\field\Field
+ * @group views
+ */
+class FieldTest extends UnitTestCase {
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityManager;
+
+  protected $formatterPluginManager;
+
+  protected $languageManager;
+
+  /**
+   * The mocked field type plugin manager.
+   *
+   * @var \Drupal\Core\Field\FieldTypePluginManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $fieldTypePluginManager;
+
+  /**
+   * The mocked view entity.
+   *
+   * @var \Drupal\views\Entity\View|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $view;
+
+  /**
+   * The mocked view executable.
+   *
+   * @var \Drupal\views\ViewExecutable|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $executable;
+
+  /**
+   * The mocked display plugin.
+   *
+   * @var \Drupal\views\Plugin\views\display\DisplayPluginBase|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $display;
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
+    $this->formatterPluginManager = $this->getMockBuilder('Drupal\Core\Field\FormatterPluginManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $this->fieldTypePluginManager = $this->getMock('Drupal\Core\Field\FieldTypePluginManagerInterface');
+    $this->fieldTypePluginManager->expects($this->any())
+      ->method('getDefaultStorageSettings')
+      ->willReturn([]);
+    $this->fieldTypePluginManager->expects($this->any())
+      ->method('getDefaultFieldSettings')
+      ->willReturn([]);
+
+    $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
+
+    $this->executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $this->view = $this->getMockBuilder('Drupal\views\Entity\View')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $this->display = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $this->executable->storage = $this->view;
+
+    $container = new ContainerBuilder();
+    $container->set('plugin.manager.field.field_type', $this->fieldTypePluginManager);
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * @covers ::defineOptions()
+   */
+  public function testDefineOptions() {
+    $definition = [
+      'entity_type' => 'test_entity',
+      'field_name' => 'title'
+    ];
+    $handler = new Field([], 'field', $definition, $this->entityManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager);
+
+    $view = $this->getMockBuilder('Drupal\views\ViewExecutable')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $display = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    // Setup the entity manager to allow fetching the storage definitions.
+    $title_storage = $this->getBaseFieldStorage();
+
+    $this->entityManager->expects($this->atLeastOnce())
+      ->method('getFieldStorageDefinitions')
+      ->with('test_entity')
+      ->willReturn([
+        'title' => $title_storage,
+      ]);
+
+    $options = [];
+    $handler->init($view, $display, $options);
+  }
+
+  /**
+   * @covers ::calculateDependencies()
+   */
+  public function testCalculateDependenciesWithBaseField() {
+    $definition = [
+      'entity_type' => 'test_entity',
+      'field_name' => 'title'
+    ];
+    $handler = new Field([], 'field', $definition, $this->entityManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager);
+
+    $title_storage = $this->getBaseFieldStorage();
+    $this->entityManager->expects($this->atLeastOnce())
+      ->method('getFieldStorageDefinitions')
+      ->with('test_entity')
+      ->willReturn([
+        'title' => $title_storage,
+      ]);
+
+    $dependencies = $handler->calculateDependencies();
+    $this->assertEmpty($dependencies);
+  }
+
+  /**
+   * @covers ::calculateDependencies()
+   */
+  public function testCalculateDependenciesWithConfiguredField() {
+    $definition = [
+      'entity_type' => 'test_entity',
+      'field_name' => 'body'
+    ];
+    $handler = new Field([], 'field', $definition, $this->entityManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager);
+
+    $body_storage = $this->getFieldStorageConfig();
+    $this->entityManager->expects($this->atLeastOnce())
+      ->method('getFieldStorageDefinitions')
+      ->with('test_entity')
+      ->willReturn([
+        'body' => $body_storage,
+      ]);
+
+    $body_storage->expects($this->atLeastOnce())
+      ->method('getConfigDependencyName')
+      ->willReturn('field.field_storage_config.body');
+
+    $dependencies = $handler->calculateDependencies();
+    $this->assertEquals(['config' => ['field.field_storage_config.body']], $dependencies);
+  }
+
+  /**
+   * @covers ::access
+   */
+  public function testAccess() {
+    $definition = [
+      'entity_type' => 'test_entity',
+      'field_name' => 'title',
+      'entity_tables' => ['test_entity_table' => 'test_entity']
+    ];
+    $handler = new Field([], 'field', $definition, $this->entityManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager);
+    $handler->view = $this->executable;
+    $this->view->expects($this->atLeastOnce())
+      ->method('get')
+      ->with('base_table')
+      ->willReturn('test_entity_table');
+
+    $access_control_handler = $this->getMock('Drupal\Core\Entity\EntityAccessControlHandlerInterface');
+    $this->entityManager->expects($this->atLeastOnce())
+      ->method('getAccessControlHandler')
+      ->with('test_entity')
+      ->willReturn($access_control_handler);
+
+    $title_storage = $this->getBaseFieldStorage();
+    $this->entityManager->expects($this->atLeastOnce())
+      ->method('getFieldStorageDefinitions')
+      ->with('test_entity')
+      ->willReturn([
+        'title' => $title_storage,
+      ]);
+
+    $account = $this->getMock('Drupal\Core\Session\AccountInterface');
+
+    $access_control_handler->expects($this->atLeastOnce())
+      ->method('fieldAccess')
+      // @todo replace the second anything() with FALSE.
+      ->with('view', $this->anything(), $account, NULL, $this->anything())
+      ->willReturn(TRUE);
+
+    $this->assertTrue($handler->access($account));
+  }
+
+  /**
+   * @dataProvider providerSortOrders
+   *
+   * @param string $order
+   *   The sort order.
+   */
+  public function testClickSortWithOutConfiguredColumn($order) {
+    $definition = [
+      'entity_type' => 'test_entity',
+      'field_name' => 'title',
+      'entity_tables' => ['test_entity_table' => 'test_entity']
+    ];
+    $handler = new Field([], 'field', $definition, $this->entityManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager);
+    $handler->view = $this->executable;
+
+    $this->entityManager->expects($this->never())
+      ->method('getFieldStorageDefinitions');
+
+    $handler->clickSort($order);
+  }
+
+  /**
+   * @dataProvider providerSortOrders
+   *
+   * @param string $order
+   *   The sort order.
+   */
+  public function testClickSortWithBaseField($order) {
+    $definition = [
+      'entity_type' => 'test_entity',
+      'field_name' => 'title',
+      'entity_tables' => ['test_entity_table' => 'test_entity']
+    ];
+    $handler = new Field([], 'field', $definition, $this->entityManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager);
+    $handler->view = $this->executable;
+
+    $field_storage = $this->getBaseFieldStorage();
+    $this->entityManager->expects($this->atLeastOnce())
+      ->method('getFieldStorageDefinitions')
+      ->with('test_entity')
+      ->willReturn([
+        'title' => $field_storage,
+      ]);
+
+    $table_mapping = $this->getMock('Drupal\Core\Entity\Sql\TableMappingInterface');
+    $table_mapping
+      ->expects($this->atLeastOnce())
+      ->method('getFieldColumnName')
+      ->with($field_storage, 'value')
+      ->willReturn('title');
+    $entity_storage = $this->getMock('Drupal\Core\Entity\Sql\SqlEntityStorageInterface');
+    $entity_storage->expects($this->atLeastOnce())
+      ->method('getTableMapping')
+      ->willReturn($table_mapping);
+    $this->entityManager->expects($this->atLeastOnce())
+      ->method('getStorage')
+      ->with('test_entity')
+      ->willReturn($entity_storage);
+
+    // Setup a click sort configuration.
+    $options = [
+      'click_sort_column' => 'value',
+      'table' => 'test_entity',
+    ];
+    $handler->init($this->executable, $this->display, $options);
+
+    $handler->query = $this->getMockBuilder('Drupal\views\Plugin\views\query\Sql')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $handler->query->expects($this->atLeastOnce())
+      ->method('ensureTable')
+      ->with('test_entity', NULL)
+      ->willReturn('test_entity');
+
+    $handler->query->expects($this->atLeastOnce())
+      ->method('addOrderBy')
+      ->with(NULL, NULL, $order, 'test_entity.title', []);
+    $handler->clickSort($order);
+  }
+
+  /**
+   * @dataProvider providerSortOrders
+   *
+   * @param string $order
+   *   The sort order.
+   */
+  public function testClickSortWithConfiguredField($order) {
+    $definition = [
+      'entity_type' => 'test_entity',
+      'field_name' => 'body',
+      'entity_tables' => ['test_entity_table' => 'test_entity']
+    ];
+    $handler = new Field([], 'field', $definition, $this->entityManager, $this->formatterPluginManager, $this->fieldTypePluginManager, $this->languageManager);
+    $handler->view = $this->executable;
+
+    $field_storage = $this->getFieldStorageConfig();
+    $this->entityManager->expects($this->atLeastOnce())
+      ->method('getFieldStorageDefinitions')
+      ->with('test_entity')
+      ->willReturn([
+        'body' => $field_storage,
+      ]);
+
+    $table_mapping = $this->getMock('Drupal\Core\Entity\Sql\TableMappingInterface');
+    $table_mapping
+      ->expects($this->atLeastOnce())
+      ->method('getFieldColumnName')
+      ->with($field_storage, 'value')
+      ->willReturn('body_value');
+    $entity_storage = $this->getMock('Drupal\Core\Entity\Sql\SqlEntityStorageInterface');
+    $entity_storage->expects($this->atLeastOnce())
+      ->method('getTableMapping')
+      ->willReturn($table_mapping);
+    $this->entityManager->expects($this->atLeastOnce())
+      ->method('getStorage')
+      ->with('test_entity')
+      ->willReturn($entity_storage);
+
+    // Setup a click sort configuration.
+    $options = [
+      'click_sort_column' => 'value',
+      'table' => 'test_entity__body',
+    ];
+    $handler->init($this->executable, $this->display, $options);
+
+    $handler->query = $this->getMockBuilder('Drupal\views\Plugin\views\query\Sql')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $handler->query->expects($this->atLeastOnce())
+      ->method('ensureTable')
+      ->with('test_entity__body', NULL)
+      ->willReturn('test_entity__body_alias');
+
+    $handler->query->expects($this->atLeastOnce())
+      ->method('addOrderBy')
+      ->with(NULL, NULL, $order, 'test_entity__body_alias.body_value', []);
+    $handler->clickSort($order);
+  }
+
+  /**
+   * @return \Drupal\Core\Field\FieldStorageDefinitionInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected function getBaseFieldStorage() {
+    $title_storage = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
+    $title_storage->expects($this->any())
+      ->method('getColumns')
+      ->willReturn(['value' => ['type' => 'varchar']]);
+    $title_storage->expects($this->any())
+      ->method('getSettings')
+      ->willReturn([]);
+    $title_storage->expects($this->any())
+      ->method('getConstraints')
+      ->willReturn([]);
+    return $title_storage;
+  }
+
+  /**
+   * @return \Drupal\field\FieldStorageConfigInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected function getFieldStorageConfig() {
+    $title_storage = $this->getMock('Drupal\field\FieldStorageConfigInterface');
+    $title_storage->expects($this->any())
+      ->method('getColumns')
+      ->willReturn(['value' => ['type' => 'varchar']]);
+    $title_storage->expects($this->any())
+      ->method('getSettings')
+      ->willReturn([]);
+    $title_storage->expects($this->any())
+      ->method('getConstraints')
+      ->willReturn([]);
+    return $title_storage;
+  }
+
+  public function providerSortOrders() {
+    return [
+      ['asc'],
+      ['desc'],
+      ['ASC'],
+      ['DESC'],
+    ];
+  }
+
+}
+
diff --git a/core/modules/field_ui/src/Tests/EntityDisplayTest.php b/core/modules/field_ui/src/Tests/EntityDisplayTest.php
index 82003d8..1ebd54f 100644
--- a/core/modules/field_ui/src/Tests/EntityDisplayTest.php
+++ b/core/modules/field_ui/src/Tests/EntityDisplayTest.php
@@ -69,7 +69,9 @@ public function testEntityDisplayCRUD() {
       'label' => 'hidden',
       'type' => 'string',
       'weight' => -5,
-      'settings' => array(),
+      'settings' => array(
+        'link_to_entity' => FALSE,
+      ),
       'third_party_settings' => array(),
     );
     $this->assertEqual($display->getComponents(), $expected);
diff --git a/core/modules/migrate_drupal/src/Tests/d6/MigrateFieldFormatterSettingsTest.php b/core/modules/migrate_drupal/src/Tests/d6/MigrateFieldFormatterSettingsTest.php
index 4759dc0..56eabf5 100644
--- a/core/modules/migrate_drupal/src/Tests/d6/MigrateFieldFormatterSettingsTest.php
+++ b/core/modules/migrate_drupal/src/Tests/d6/MigrateFieldFormatterSettingsTest.php
@@ -178,7 +178,7 @@ public function testEntityDisplaySettings() {
     // Test phone field.
     $expected['weight'] = 9;
     $expected['type'] = 'string';
-    $expected['settings'] = array();
+    $expected['settings'] = array('link_to_entity' => FALSE);
     $component = $display->getComponent('field_test_phone');
     $this->assertEqual($component, $expected, "node.story.teaser field_test_phone is of type telephone.");
 
diff --git a/core/modules/node/src/NodeViewsData.php b/core/modules/node/src/NodeViewsData.php
index b3df204..01b68dc 100644
--- a/core/modules/node/src/NodeViewsData.php
+++ b/core/modules/node/src/NodeViewsData.php
@@ -33,7 +33,12 @@ public function getViewsData() {
       'validate type' => 'nid',
     ];
 
-    $data['node_field_data']['title']['field']['id'] = 'node';
+    // @fixme Move this into the generic views data.
+    $data['node_field_data']['title']['field']['id'] = 'field';
+    $data['node_field_data']['title']['field']['field_name'] = 'title';
+    $data['node_field_data']['title']['field']['entity_tables'] = ['node' => 'node', 'node_field_data' => 'node'];
+    $data['node_field_data']['title']['field']['default_formatter_settings'] = ['entity_link' => TRUE];
+
     $data['node_field_data']['title']['field']['link_to_node default'] = TRUE;
 
     $data['node_field_data']['type']['field']['id'] = 'node_type';
diff --git a/core/modules/node/src/Plugin/views/wizard/Node.php b/core/modules/node/src/Plugin/views/wizard/Node.php
index 05cf100..eb294a0 100644
--- a/core/modules/node/src/Plugin/views/wizard/Node.php
+++ b/core/modules/node/src/Plugin/views/wizard/Node.php
@@ -85,6 +85,7 @@ protected function defaultDisplayOptions() {
     $display_options['fields']['title']['id'] = 'title';
     $display_options['fields']['title']['table'] = 'node_field_data';
     $display_options['fields']['title']['field'] = 'title';
+    $display_options['fields']['title']['entity_type'] = 'node';
     $display_options['fields']['title']['label'] = '';
     $display_options['fields']['title']['alter']['alter_text'] = 0;
     $display_options['fields']['title']['alter']['make_link'] = 0;
diff --git a/core/modules/simpletest/src/AssertContentTrait.php b/core/modules/simpletest/src/AssertContentTrait.php
index 5fdafdf..e114ebf 100644
--- a/core/modules/simpletest/src/AssertContentTrait.php
+++ b/core/modules/simpletest/src/AssertContentTrait.php
@@ -141,6 +141,16 @@ protected function parse() {
   }
 
   /**
+   * Get the current URL from the cURL handler.
+   *
+   * @return string
+   *   The current URL.
+   */
+  protected function getUrl() {
+    return isset($this->url) ? $this->url : 'no-url';
+  }
+
+  /**
    * Builds an XPath query.
    *
    * Builds an XPath query by replacing placeholders in the query by the value
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index 44af34c..fabcc26 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -2308,16 +2308,6 @@ protected function getAbsoluteUrl($path) {
   }
 
   /**
-   * Get the current URL from the cURL handler.
-   *
-   * @return
-   *   The current URL.
-   */
-  protected function getUrl() {
-    return $this->url;
-  }
-
-  /**
    * Gets the HTTP response headers of the requested page.
    *
    * Normally we are only interested in the headers returned by the last
diff --git a/core/modules/tracker/src/Tests/Views/TrackerUserUidTest.php b/core/modules/tracker/src/Tests/Views/TrackerUserUidTest.php
index 7c9be32..ce5bbab 100644
--- a/core/modules/tracker/src/Tests/Views/TrackerUserUidTest.php
+++ b/core/modules/tracker/src/Tests/Views/TrackerUserUidTest.php
@@ -29,13 +29,11 @@ class TrackerUserUidTest extends TrackerTestBase {
   public function testUserUid() {
     $map = array(
       'nid' => 'nid',
-      'node_field_data_title' => 'title',
     );
 
     $expected = array(
       array(
         'nid' => $this->node->id(),
-        'title' => $this->node->label(),
       )
     );
 
diff --git a/core/modules/views/src/Plugin/ViewsHandlerManager.php b/core/modules/views/src/Plugin/ViewsHandlerManager.php
index 146c6a8..eafc758 100644
--- a/core/modules/views/src/Plugin/ViewsHandlerManager.php
+++ b/core/modules/views/src/Plugin/ViewsHandlerManager.php
@@ -91,7 +91,7 @@ public function getHandler($item, $override = NULL) {
 
     if (isset($data[$field][$this->handlerType])) {
       $definition = $data[$field][$this->handlerType];
-      foreach (array('group', 'title', 'title short', 'help', 'real field', 'real table') as $key) {
+      foreach (array('group', 'title', 'title short', 'help', 'real field', 'real table', 'entity type') as $key) {
         if (!isset($definition[$key])) {
           // First check the field level.
           if (!empty($data[$field][$key])) {
@@ -99,7 +99,8 @@ public function getHandler($item, $override = NULL) {
           }
           // Then if that doesn't work, check the table level.
           elseif (!empty($data['table'][$key])) {
-            $definition[$key] = $data['table'][$key];
+            $definition_key = $key === 'entity type' ? 'entity_type' : $key;
+            $definition[$definition_key] = $data['table'][$key];
           }
         }
       }
diff --git a/core/tests/Drupal/Tests/Core/Entity/Sql/DefaultTableMappingTest.php b/core/tests/Drupal/Tests/Core/Entity/Sql/DefaultTableMappingTest.php
index 007efc3..cb29029 100644
--- a/core/tests/Drupal/Tests/Core/Entity/Sql/DefaultTableMappingTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/Sql/DefaultTableMappingTest.php
@@ -235,6 +235,36 @@ public function testGetExtraColumns() {
   }
 
   /**
+   * @dataProvider providerTestGetFieldColumnName
+   */
+  public function testGetFieldColumnName($base_field, $columns, $column, $expected) {
+    $definitions['test'] = $this->setUpDefinition('test', $columns, $base_field);
+    $table_mapping = new DefaultTableMapping($definitions);
+
+    $result = $table_mapping->getFieldColumnName($definitions['test'], $column);
+    $this->assertEquals($expected, $result);
+  }
+
+  public function providerTestGetFieldColumnName() {
+    $data = [];
+    // Base field with single column.
+    $data[] = [TRUE, ['foo'], 'foo', 'test'];
+
+    // Base field with multiple columns.
+    $data[] = [TRUE, ['foo', 'bar'], 'foo', 'test_foo'];
+    $data[] = [TRUE, ['foo', 'bar'], 'bar', 'test_bar'];
+    // Configured field with single column.
+    $data[] = [FALSE, ['foo'], 'foo', 'test_foo'];
+    // Configured field with multiple columns.
+    $data[] = [FALSE, ['foo', 'bar'], 'foo', 'test_foo'];
+    $data[] = [FALSE, ['foo', 'bar'], 'bar', 'test_bar'];
+    // Check for reserved columns.
+    $data[] = [TRUE, ['foo', 'bar'], 'deleted', 'deleted'];
+
+    return $data;
+  }
+
+  /**
    * Sets up a field storage definition for the test.
    *
    * @param string $name
@@ -244,11 +274,11 @@ public function testGetExtraColumns() {
    *
    * @return \Drupal\Core\Field\FieldStorageDefinitionInterface|\PHPUnit_Framework_MockObject_MockObject
    */
-  protected function setUpDefinition($name, array $column_names) {
+  protected function setUpDefinition($name, array $column_names, $base_field = TRUE) {
     $definition = $this->getMock('Drupal\Tests\Core\Field\TestBaseFieldDefinitionInterface');
     $definition->expects($this->any())
       ->method('isBaseField')
-      ->will($this->returnValue(TRUE));
+      ->willReturn($base_field);
     $definition->expects($this->any())
       ->method('getName')
       ->will($this->returnValue($name));
