diff --git a/core/modules/views/src/EntityViewsData.php b/core/modules/views/src/EntityViewsData.php
index cc7b7be..c2d95b7 100644
--- a/core/modules/views/src/EntityViewsData.php
+++ b/core/modules/views/src/EntityViewsData.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\views;
 
+use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Entity\ContentEntityType;
 use Drupal\Core\Entity\EntityHandlerInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
@@ -58,6 +60,13 @@ class EntityViewsData implements EntityHandlerInterface, EntityViewsDataInterfac
   protected $fieldStorageDefinitions;
 
   /**
+   * The field type views data.
+   *
+   * @var \Drupal\Component\Plugin\PluginManagerInterface
+   */
+  protected $fieldTypeViewsData;
+
+  /**
    * Constructs an EntityViewsData object.
    *
    * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
@@ -71,12 +80,13 @@ class EntityViewsData implements EntityHandlerInterface, EntityViewsDataInterfac
    * @param \Drupal\Core\StringTranslation\TranslationInterface $translation_manager
    *   The translation manager.
    */
-  function __construct(EntityTypeInterface $entity_type, SqlEntityStorageInterface $storage_controller, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, TranslationInterface $translation_manager) {
+  function __construct(EntityTypeInterface $entity_type, SqlEntityStorageInterface $storage_controller, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, TranslationInterface $translation_manager, PluginManagerInterface $field_type_views_data) {
     $this->entityType = $entity_type;
     $this->entityManager = $entity_manager;
     $this->storage = $storage_controller;
     $this->moduleHandler = $module_handler;
     $this->setStringTranslation($translation_manager);
+    $this->fieldTypeViewsData = $field_type_views_data;
   }
 
   /**
@@ -89,7 +99,8 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
       $container->get('entity.manager'),
       $container->get('module_handler'),
       $container->get('string_translation'),
-      $container->get('typed_data_manager')
+      $container->get('typed_data_manager'),
+      $container->get('plugin.manager.views.field_type_views_data')
     );
   }
 
@@ -324,7 +335,8 @@ protected function addEntityLinks(array &$data) {
   protected function mapFieldDefinition($table, $field_name, FieldDefinitionInterface $field_definition, TableMappingInterface $table_mapping, &$table_data) {
     // Create a dummy instance to retrieve property definitions.
     $field_column_mapping = $table_mapping->getColumnNames($field_name);
-    $field_schema = $this->getFieldStorageDefinitions()[$field_name]->getSchema();
+    $field_storage_definition = $this->getFieldStorageDefinitions()[$field_name];
+    $field_schema = $field_storage_definition->getSchema();
 
     $field_definition_type = $field_definition->getType();
     // Add all properties to views table data. We need an entry for each
@@ -334,13 +346,27 @@ protected function mapFieldDefinition($table, $field_name, FieldDefinitionInterf
     //   mapSingleFieldViewsData() method does with $first.
     $multiple = (count($field_column_mapping) > 1);
     $first = TRUE;
+
+    $data = [];
+    /** @var \Drupal\views\Plugin\views\FieldTypeViewsDataInterface $field_type_views_data_plugin */
+    $field_type_views_data_plugin = $this->fieldTypeViewsData->createInstance($field_definition_type);
     foreach ($field_column_mapping as $field_column_name => $schema_field_name) {
       $views_field_name = ($multiple) ? $field_name . '__' . $field_column_name : $field_name;
-      $table_data[$views_field_name] = $this->mapSingleFieldViewsData($table, $field_name, $field_definition_type, $field_column_name, $field_schema['columns'][$field_column_name]['type'], $first, $field_definition);
 
-      $table_data[$views_field_name]['entity field'] = $field_name;
+      if ($field_type_views_data_plugin) {
+        $data[$views_field_name] = $field_type_views_data_plugin->getViewsData($field_storage_definition, $field_column_name);
+      }
+      else {
+        $data[$views_field_name] = $this->mapSingleFieldViewsData($table, $field_name, $field_definition_type, $field_column_name, $field_schema['columns'][$field_column_name]['type'], $first, $field_definition);
+      }
+
+      $data[$views_field_name]['entity field'] = $field_name;
       $first = FALSE;
     }
+
+    $this->moduleHandler->alter('field_type_views_data_alter', $data, $field_definition, $field_storage_definition);
+
+    $table_data = NestedArray::mergeDeep($table_data, $data);
   }
 
   /**
@@ -403,13 +429,6 @@ protected function mapSingleFieldViewsData($table, $field_name, $field_type, $co
         $views_field['sort']['id'] = 'standard';
         break;
 
-      case 'boolean':
-        $views_field['field']['id'] = 'field';
-        $views_field['argument']['id'] = 'numeric';
-        $views_field['filter']['id'] = 'boolean';
-        $views_field['sort']['id'] = 'standard';
-        break;
-
       case 'uri':
         // Let's render URIs as URIs by default, not links.
         $views_field['field']['id'] = 'field';
@@ -502,54 +521,6 @@ protected function processViewsDataForLanguage($table, FieldDefinitionInterface
   }
 
   /**
-   * Processes the views data for an entity reference field.
-   *
-   * @param string $table
-   *   The table the language field is added to.
-   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
-   *   The field definition.
-   * @param array $views_field
-   *   The views field data.
-   * @param string $field_column_name
-   *   The field column being processed.
-   */
-  protected function processViewsDataForEntityReference($table, FieldDefinitionInterface $field_definition, array &$views_field, $field_column_name) {
-
-    // @todo Should the actual field handler respect that this just renders a
-    //   number?
-    // @todo Create an optional entity field handler, that can render the
-    //   entity.
-    // @see https://www.drupal.org/node/2322949
-
-    if ($entity_type_id = $field_definition->getItemDefinition()->getSetting('target_type')) {
-      $entity_type = $this->entityManager->getDefinition($entity_type_id);
-      if ($entity_type instanceof ContentEntityType) {
-        $views_field['relationship'] = [
-          'base' => $this->getViewsTableForEntityType($entity_type),
-          'base field' => $entity_type->getKey('id'),
-          'label' => $entity_type->getLabel(),
-          'title' => $entity_type->getLabel(),
-          'id' => 'standard',
-        ];
-        $views_field['field']['id'] = 'field';
-        $views_field['argument']['id'] = 'numeric';
-        $views_field['filter']['id'] = 'numeric';
-        $views_field['sort']['id'] = 'standard';
-      }
-      else {
-        $views_field['field']['id'] = 'field';
-        $views_field['argument']['id'] = 'string';
-        $views_field['filter']['id'] = 'string';
-        $views_field['sort']['id'] = 'standard';
-      }
-    }
-
-    if ($field_definition->getName() == $this->entityType->getKey('bundle')) {
-      $views_field['filter']['id'] = 'bundle';
-    }
-  }
-
-  /**
    * Processes the views data for a text field with formatting.
    *
    * @param string $table
diff --git a/core/modules/views/src/Plugin/views/FieldTypeViewsData/Boolean.php b/core/modules/views/src/Plugin/views/FieldTypeViewsData/Boolean.php
new file mode 100644
index 0000000..2311725
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/FieldTypeViewsData/Boolean.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Drupal\views\Plugin\views\FieldTypeViewsData;
+
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\views\Plugin\views\FieldTypeViewsDataInterface;
+
+/**
+ * @Plugin(
+ *   "id" = "boolean",
+ * )
+ */
+class Boolean implements FieldTypeViewsDataInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getViewsData(FieldStorageDefinitionInterface $field_storage, $column_name) {
+    $views_field = [];
+
+    // Provide a nicer, less verbose label for the first column within a field.
+    if ($field_storage->getMainPropertyName() == $column_name) {
+      $views_field['title'] = $field_storage->getLabel();
+    }
+    else {
+      $views_field['title'] = $field_storage->getLabel() . " ($column_name)";
+    }
+
+    if ($description = $field_storage->getDescription()) {
+      $views_field['help'] = $description;
+    }
+
+    $views_field['field']['id'] = 'field';
+    $views_field['argument']['id'] = 'numeric';
+    $views_field['filter']['id'] = 'boolean';
+    $views_field['sort']['id'] = 'standard';
+
+    return $views_field;
+  }
+
+}
diff --git a/core/modules/views/src/Plugin/views/FieldTypeViewsData/EntityReference.php b/core/modules/views/src/Plugin/views/FieldTypeViewsData/EntityReference.php
new file mode 100644
index 0000000..c78b598
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/FieldTypeViewsData/EntityReference.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Drupal\views\Plugin\views\FieldTypeViewsData;
+
+use Drupal\Core\Entity\ContentEntityType;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\views\Plugin\views\FieldTypeViewsDataInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+
+/**
+ * @Plugin(
+ *   "id" = "entity_reference",
+ * )
+ */
+class EntityReference implements FieldTypeViewsDataInterface, ContainerFactoryPluginInterface {
+
+  /** @var \Drupal\Core\Entity\EntityTypeManagerInterface */
+  protected $entityTypeManager;
+
+  /**
+   * Creates a new EntityReference instance.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
+   *   The entity type manager.
+   */
+  public function __construct(EntityTypeManagerInterface $entityTypeManager) {
+    $this->entityTypeManager = $entityTypeManager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $container->get('entity_type.manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getViewsData(FieldStorageDefinitionInterface $field_storage, $column_name) {
+    // @todo Should the actual field handler respect that this just renders a
+    //   number?
+    // @todo Create an optional entity field handler, that can render the
+    //   entity.
+    // @see https://www.drupal.org/node/2322949
+    $views_field = [];
+
+    /** @var \Drupal\views\EntityViewsDataInterface $views_data */
+    $views_data = $this->entityTypeManager->getHandler($field_storage->getTargetEntityTypeId(), 'views_data');
+
+    if ($entity_type_id = $field_storage->getSetting('target_type')) {
+      $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
+      if ($entity_type instanceof ContentEntityType) {
+        $views_field['relationship'] = [
+          'base' => $views_data->getViewsTableForEntityType($entity_type),
+          'base field' => $entity_type->getKey('id'),
+          'label' => $entity_type->getLabel(),
+          'title' => $entity_type->getLabel(),
+          'id' => 'standard',
+        ];
+        $views_field['field']['id'] = 'field';
+        $views_field['argument']['id'] = 'numeric';
+        $views_field['filter']['id'] = 'numeric';
+        $views_field['sort']['id'] = 'standard';
+      }
+      else {
+        $views_field['field']['id'] = 'field';
+        $views_field['argument']['id'] = 'string';
+        $views_field['filter']['id'] = 'string';
+        $views_field['sort']['id'] = 'standard';
+      }
+    }
+
+    if ($field_storage->getName() == $this->entityTypeManager->getDefinition($field_storage->getTargetEntityTypeId())->getKey('bundle')) {
+      $views_field['filter']['id'] = 'bundle';
+    }
+
+    return $views_field;
+  }
+
+}
diff --git a/core/modules/views/src/Plugin/views/FieldTypeViewsDataInterface.php b/core/modules/views/src/Plugin/views/FieldTypeViewsDataInterface.php
new file mode 100644
index 0000000..3bdc346
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/FieldTypeViewsDataInterface.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Drupal\views\Plugin\views;
+
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+
+interface FieldTypeViewsDataInterface {
+
+  /**
+   * @return array
+   */
+  public function getViewsData(FieldStorageDefinitionInterface $field_storage, $column_name);
+
+}
diff --git a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
index c1db0cf..ecf6ff4 100644
--- a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
+++ b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
@@ -7,11 +7,13 @@
 
 namespace Drupal\Tests\views\Unit {
 
-use Drupal\Core\Config\Entity\ConfigEntityType;
+  use Drupal\Component\Plugin\PluginManagerInterface;
+  use Drupal\Core\Config\Entity\ConfigEntityType;
 use Drupal\Core\Entity\ContentEntityType;
 use Drupal\Core\Entity\EntityType;
 use Drupal\Core\Entity\EntityTypeInterface;
-use Drupal\Core\Field\BaseFieldDefinition;
+  use Drupal\Core\Entity\EntityTypeManagerInterface;
+  use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
 use Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem;
 use Drupal\Core\Field\Plugin\Field\FieldType\LanguageItem;
@@ -25,7 +27,10 @@
 use Drupal\entity_test\Entity\EntityTestMulRev;
 use Drupal\Tests\UnitTestCase;
 use Drupal\views\EntityViewsData;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
+  use Drupal\views\Plugin\views\FieldTypeViewsData\Boolean;
+  use Drupal\views\Plugin\views\FieldTypeViewsData\EntityReference;
+  use Prophecy\Argument;
+  use Symfony\Component\DependencyInjection\ContainerBuilder;
 
 /**
  * @coversDefaultClass \Drupal\views\EntityViewsData
@@ -106,7 +111,7 @@ protected function setUp() {
     $this->translationManager = $this->getStringTranslationStub();
     $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
 
-    $this->viewsData = new TestEntityViewsData($this->baseEntityType, $this->entityStorage, $this->entityManager, $this->moduleHandler, $this->translationManager);
+    $this->viewsData = new TestEntityViewsData($this->baseEntityType, $this->entityStorage, $this->entityManager, $this->moduleHandler, $this->translationManager, $this->setupFieldTypeViewsData($this->entityManager));
 
     $field_type_manager = $this->getMockBuilder('Drupal\Core\Field\FieldTypePluginManager')
       ->disableOriginalConstructor()
@@ -126,6 +131,17 @@ protected function setUp() {
   }
 
   /**
+   * @return \Drupal\Component\Plugin\PluginManagerInterface
+   */
+  protected function setupFieldTypeViewsData(EntityTypeManagerInterface $entity_type_manager) {
+    $field_type_views_data_manager = $this->prophesize(PluginManagerInterface::class);
+    $field_type_views_data_manager->createInstance('boolean')->willReturn(new Boolean());
+    $field_type_views_data_manager->createInstance('entity_reference')->willReturn(new EntityReference($entity_type_manager));
+    $field_type_views_data_manager->createInstance(Argument::any())->willReturn(NULL);
+    return $field_type_views_data_manager->reveal();
+  }
+
+  /**
    * Helper method to setup base fields.
    *
    * @param \Drupal\Core\Field\BaseFieldDefinition[] $base_fields
diff --git a/core/modules/views/views.services.yml b/core/modules/views/views.services.yml
index 1a01543..3dcebe5 100644
--- a/core/modules/views/views.services.yml
+++ b/core/modules/views/views.services.yml
@@ -56,6 +56,9 @@ services:
   plugin.manager.views.wizard:
     class: Drupal\views\Plugin\ViewsPluginManager
     arguments: [wizard, '@container.namespaces', '@cache.discovery', '@module_handler']
+  plugin.manager.views.field_type_views_data:
+    class: \Drupal\Core\Plugin\DefaultPluginManager
+    parent: default_plugin_manager
   views.views_data:
     class: Drupal\views\ViewsData
     arguments: ['@cache.discovery', '@config.factory', '@module_handler', '@language_manager']
diff --git a/core/modules/views/views.views.inc b/core/modules/views/views.views.inc
index aca4b8a..05bdd67 100644
--- a/core/modules/views/views.views.inc
+++ b/core/modules/views/views.views.inc
@@ -176,19 +176,30 @@ function views_views_data() {
   $module_handler = \Drupal::moduleHandler();
 
   $entity_manager = \Drupal::entityManager();
+  /** @var \Drupal\Component\Plugin\PluginManagerInterface $field_type_views_data */
+  $field_type_views_data = \Drupal::service('plugin.manager.views.field_type_views_data');
   if ($entity_manager->hasDefinition('field_storage_config')) {
     /** @var \Drupal\field\FieldStorageConfigInterface $field_storage */
     foreach ($entity_manager->getStorage('field_storage_config')->loadMultiple() as $field_storage) {
       if (_views_field_get_entity_type_storage($field_storage)) {
-        $result = (array) $module_handler->invoke($field_storage->getTypeProvider(), 'field_views_data', array($field_storage));
-        if (empty($result)) {
-          $result = views_field_default_views_data($field_storage);
+
+        /** @var \Drupal\views\Plugin\views\FieldTypeViewsDataInterface $field_type_views_data_plugin */
+        if ($field_type_views_data_plugin = $field_type_views_data->createInstance($field_storage->getType())) {
+          $result = $field_type_views_data_plugin->getViewsData($field_storage);
+        }
+        else {
+          $result = (array) $module_handler->invoke($field_storage->getTypeProvider(), 'field_views_data', array($field_storage));
+          if (empty($result)) {
+            $result = views_field_default_views_data($field_storage);
+          }
         }
         $module_handler->alter('field_views_data', $result, $field_storage);
 
         if (is_array($result)) {
           $data = NestedArray::mergeDeep($result, $data);
         }
+
+        
       }
     }
   }
