diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php
index 392b564..9b144fe 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php
@@ -26,7 +26,8 @@
  *     "form" = {
  *       "default" = "Drupal\entity_test\EntityTestFormController"
  *     },
- *     "translation" = "Drupal\content_translation\ContentTranslationController"
+ *     "translation" = "Drupal\content_translation\ContentTranslationController",
+ *     "views" = "Drupal\views\EntityViewsController"
  *   },
  *   base_table = "entity_test",
  *   fieldable = TRUE,
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMul.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMul.php
index 76db7ab..a669bce 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMul.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMul.php
@@ -24,7 +24,8 @@
  *     "form" = {
  *       "default" = "Drupal\entity_test\EntityTestFormController"
  *     },
- *     "translation" = "Drupal\content_translation\ContentTranslationController"
+ *     "translation" = "Drupal\content_translation\ContentTranslationController",
+ *     "views" = "Drupal\views\EntityViewsController"
  *   },
  *   base_table = "entity_test_mul",
  *   data_table = "entity_test_mul_property_data",
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMulRev.php
index 407640b..05a0d1f 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMulRev.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestMulRev.php
@@ -24,7 +24,8 @@
  *     "form" = {
  *       "default" = "Drupal\entity_test\EntityTestFormController"
  *     },
- *     "translation" = "Drupal\content_translation\ContentTranslationController"
+ *     "translation" = "Drupal\content_translation\ContentTranslationController",
+ *     "views" = "Drupal\views\EntityViewsController"
  *   },
  *   base_table = "entity_test_mulrev",
  *   data_table = "entity_test_mulrev_property_data",
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestRev.php
index 1c2c882..0d3c75b 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestRev.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestRev.php
@@ -24,7 +24,8 @@
  *     "form" = {
  *       "default" = "Drupal\entity_test\EntityTestFormController"
  *     },
- *     "translation" = "Drupal\content_translation\ContentTranslationController"
+ *     "translation" = "Drupal\content_translation\ContentTranslationController",
+ *     "views" = "Drupal\views\EntityViewsController"
  *   },
  *   base_table = "entity_test_rev",
  *   revision_table = "entity_test_rev_revision",
diff --git a/core/modules/views/lib/Drupal/views/EntityViewsController.php b/core/modules/views/lib/Drupal/views/EntityViewsController.php
new file mode 100644
index 0000000..4369a73
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/EntityViewsController.php
@@ -0,0 +1,194 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\EntityViewsController.
+ */
+
+namespace Drupal\views;
+
+use Drupal\Core\Entity\EntityControllerInterface;
+use Drupal\Core\Entity\EntityManager;
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a generic views integration of entity-NG.
+ */
+class EntityViewsController implements EntityControllerInterface {
+
+  /**
+   * Entity type for this views controller instance.
+   *
+   * @var string
+   */
+  protected $entityType;
+
+  /**
+   * Array of information about the entity type.
+   *
+   * @var array
+   *
+   * @see entity_get_info()
+   */
+  protected $entityInfo;
+
+  /**
+   * The storage controller used for this entity type.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
+   */
+  protected $storageController;
+
+  /**
+   * Constructs a EntityViewsController object.
+   *
+   * @param string $entity_type
+   *   The entity type to provide views integration for.
+   * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage_controller
+   *   The storage controller used for this entity type.
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager.
+   */
+  function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage_controller, EntityManager $entity_manager) {
+    $this->entityType = $entity_type;
+    $this->entityInfo = $entity_info;
+    $this->entityManager = $entity_manager;
+    $this->storageController = $storage_controller;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+    return new static(
+      $entity_type,
+      $entity_info,
+      $container->get('entity.manager')->getStorageController($entity_type),
+      $container->get('entity.manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function viewsData() {
+    $data = array();
+    $base_table = $this->entityInfo['base_table'];
+    $base_field = $this->entityInfo['entity_keys']['id'];
+    $data_table = isset($this->entityInfo['data_table']) ? $this->entityInfo['data_table']: NULL;
+    $revision_table = isset($this->entityInfo['revision_table']) ? $this->entityInfo['revision_table'] : NULL;
+    $revision_field = isset($this->entityInfo['entity_keys']['revision']) ? $this->entityInfo['entity_keys']['revision'] : NULL;
+
+    // Setup base information of the views data.
+    $data[$base_table]['table']['entity_type'] = $this->entityType;
+    $data[$base_table]['table']['group'] = $this->entityInfo['label'];
+    $data[$base_table]['table']['base'] = array(
+      'field' => $base_field,
+      'title' => $this->entityInfo['label'],
+    );
+
+    // Setup relations to the revisions/property data.
+    if ($data_table) {
+      $data[$data_table]['table']['join'][$base_table] = array(
+        'left_field' => $base_field,
+        'field' => $base_field
+      );
+
+    }
+    if ($revision_table) {
+      $data[$revision_table]['table']['entity_type'] = $this->entityType;
+      $data[$revision_table]['table']['group'] = $this->entityInfo['label'];
+      $data[$revision_table]['table']['base'] = array(
+        'field' => $revision_field,
+        'title' => t('@entity_type revisions', array('@entity_type' => $this->entityInfo['label'])),
+      );
+      $data[$revision_table]['table']['join'][$base_table] = array(
+        'left_field' => $base_field,
+        'field' => $base_field,
+      );
+    }
+
+    // Load all typed data definitions of all fields.
+    $field_definitions = $this->entityManager->getFieldDefinitions($this->entityType);
+
+    foreach (array('base_table', 'data_table', 'revision_table', 'revision_data_table') as $table_key) {
+      if (!isset($this->entityInfo[$table_key])) {
+        continue;
+      }
+
+      $table = $this->entityInfo[$table_key];
+
+      foreach (drupal_schema_fields_sql($this->entityInfo[$table_key]) as $field_name) {
+        if (isset($field_definitions[$field_name])) {
+          $views_field = &$data[$table][$field_name];
+          // @todo Is translating the right way to handle label/description?
+          $views_field['title'] = t($field_definitions[$field_name]['label']);
+          $views_field['help'] = t($field_definitions[$field_name]['description']);
+          // @todo Find a proper find the mappings between typed data and views
+          //   handlers. Maybe the data types should define it with fallback to
+          //   standard or views should have the same naming scheme.
+          $views_field = $this->mapTypedDataHandlerId($field_definitions[$field_name], $views_field);
+        }
+      }
+    }
+
+    return $data;
+  }
+
+  /**
+   * @todo
+   */
+  protected function mapTypedDataHandlerId($typed_data, $views_field) {
+    switch ($typed_data['type']) {
+      case 'field_item:integer':
+        $views_field['field']['id'] = 'numeric';
+        $views_field['argument']['id'] = 'numeric';
+        $views_field['filter']['id'] = 'numeric';
+        $views_field['sort']['id'] = 'standard';
+        break;
+      case 'field_item:string':
+        $views_field['field']['id'] = 'standard';
+        $views_field['argument']['id'] = 'string';
+        $views_field['filter']['id'] = 'string';
+        $views_field['sort']['id'] = 'standard';
+        break;
+      case 'field_item:language':
+        $views_field['field']['id'] = 'language';
+        $views_field['argument']['id'] = 'language';
+        $views_field['filter']['id'] = 'language';
+        $views_field['sort']['id'] = 'standard';
+        break;
+      case 'field_item:boolean':
+        $views_field['field']['id'] = 'boolean';
+        $views_field['argument']['id'] = 'numeric';
+        $views_field['filter']['id'] = 'boolean';
+        $views_field['sort']['id'] = 'standard';
+        break;
+      case 'field_item:uuid':
+        $views_field['field']['id'] = 'standard';
+        $views_field['argument']['id'] = 'string';
+        $views_field['filter']['id'] = 'string';
+        break;
+      case'field_item:entity_reference':
+        // @todo No idea to determine how to find out whether the field is a number/string ID.
+        // @todo Should the actual field handler respect that this is just renders a number
+        // @todo Create an optional entity field handler.
+        $views_field['field']['id'] = 'numeric';
+        $views_field['argument']['id'] = 'numeric';
+        $views_field['filter']['id'] = 'numeric';
+        $views_field['sort']['id'] = 'standard';
+
+        $entity_type = $typed_data['settings']['target_type'];
+        $entity_info = $this->entityManager->getDefinition($entity_type);
+        $views_field['relationship'] = array(
+          'base' => $entity_info['base_table'],
+          'base field' => $entity_info['entity_keys']['id'],
+          'label' => t($typed_data['label']),
+          'id' => 'standard',
+        );
+    }
+    return $views_field;
+  }
+
+}
diff --git a/core/modules/views/lib/Drupal/views/EntityViewsControllerInterface.php b/core/modules/views/lib/Drupal/views/EntityViewsControllerInterface.php
new file mode 100644
index 0000000..47c3d71
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/EntityViewsControllerInterface.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\EntityViewsControllerInterface.
+ */
+
+namespace Drupal\views;
+
+/**
+ * Defines an interface for a entity views controller.
+ */
+interface EntityViewsControllerInterface {
+
+  /**
+   * Returns views data for a certain entity type.
+   *
+   * @return array
+   *
+   * @see hook_views_data().
+   */
+  public function viewsData();
+}
diff --git a/core/modules/views/lib/Drupal/views/Tests/EntityViewsControllerTest.php b/core/modules/views/lib/Drupal/views/Tests/EntityViewsControllerTest.php
new file mode 100644
index 0000000..0851a22
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Tests/EntityViewsControllerTest.php
@@ -0,0 +1,145 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Tests\EntityViewsControllerTest.
+ */
+
+namespace Drupal\views\Tests;
+
+/**
+ * Tests the generic entity views controller on the entity_test entity type.
+ *
+ * @see \Drupal\entity\EntityViewsController
+ */
+class EntityViewsControllerTest extends ViewTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('entity_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity views controller',
+      'description' => 'Tests the generic entity views controller on the entity_test entity type.',
+      'group' => 'Views',
+    );
+  }
+
+  /**
+   * Tests the expected views data of entity_test.
+   */
+  public function testViewsData() {
+    $entity_test_combinations = array();
+    $entity_test_combinations['entity_test'] = array('base' => 'entity_test');
+    $entity_test_combinations['entity_test_mul'] = array('base' => 'entity_test_mul', 'data' => 'entity_test_mul_property_data');
+    $entity_test_combinations['entity_test_rev'] = array('base' => 'entity_test_rev', 'revision' => 'entity_test_rev_revision');
+    $entity_test_combinations['entity_test_mulrev'] = array('base' => 'entity_test_mulrev', 'data' => 'entity_test_mulrev_property_data', 'revision' => 'entity_test_mulrev_property_revision');
+
+    $views_data_cache = $this->container->get('views.views_data');
+
+    foreach ($entity_test_combinations as $entity_type => $features) {
+
+      $views_data = $views_data_cache->get('entity_test');
+
+      $this->assertEqual('id', $views_data['table']['base']['field']);
+      $this->assertEqual(t('Entity test'), $views_data['table']['base']['title']);
+
+      // Tests the main entity table views fields.
+      // @todo Quite dump simple testing.
+      $this->assertEqual($views_data['id']['field']['id'], 'numeric');
+      $this->assertEqual($views_data['id']['filter']['id'], 'numeric');
+      $this->assertEqual($views_data['id']['argument']['id'], 'numeric');
+      $this->assertEqual($views_data['id']['sort']['id'], 'standard');
+
+      $this->assertEqual($views_data['uuid']['field']['id'], 'standard');
+      $this->assertEqual($views_data['uuid']['filter']['id'], 'string');
+      $this->assertEqual($views_data['uuid']['argument']['id'], 'string');
+      $this->assertEqual($views_data['uuid']['sort']['id'], 'standard');
+
+      // @todo Does it make sense to just integrate the langcode column once
+      //   language module is enabled?
+      $this->assertEqual($views_data['langcode']['field']['id'], 'language');
+      $this->assertEqual($views_data['langcode']['filter']['id'], 'language');
+      $this->assertEqual($views_data['langcode']['argument']['id'], 'language');
+      $this->assertEqual($views_data['langcode']['sort']['id'], 'standard');
+
+      if (isset($features['data'])) {
+        $property_views_data = $views_data_cache->get($features['data']);
+
+        // Tests the join definition between the base and the revision table.
+        $this->assertEqual($property_views_data['table']['join'][$features['base']], array(
+          'left_field' => 'id',
+          'field' => 'id',
+        ));
+        debug($property_views_data);
+
+        // Tests the property data table views fields.
+        $this->assertEqual($property_views_data['revision_id']['field']['id'], 'numeric');
+        $this->assertEqual($property_views_data['revision_id']['filter']['id'], 'numeric');
+        $this->assertEqual($property_views_data['revision_id']['argument']['id'], 'numeric');
+        $this->assertEqual($property_views_data['revision_id']['sort']['id'], 'standard');
+
+        $this->assertEqual($property_views_data['default_langcode']['field']['id'], 'boolean');
+        $this->assertEqual($property_views_data['default_langcode']['filter']['id'], 'boolean');
+        $this->assertEqual($property_views_data['default_langcode']['argument']['id'], 'numeric');
+        $this->assertEqual($property_views_data['default_langcode']['sort']['id'], 'standard');
+
+        $this->assertEqual($property_views_data['name']['field']['id'], 'standard');
+        $this->assertEqual($property_views_data['name']['filter']['id'], 'string');
+        $this->assertEqual($property_views_data['name']['argument']['id'], 'string');
+        $this->assertEqual($property_views_data['name']['sort']['id'], 'standard');
+
+        $this->assertEqual($property_views_data['user_id']['field']['id'], 'numeric');
+        $this->assertEqual($property_views_data['user_id']['filter']['id'], 'numeric');
+        $this->assertEqual($property_views_data['user_id']['argument']['id'], 'numeric');
+        $this->assertEqual($property_views_data['user_id']['relationship']['id'], 'standard');
+        $this->assertEqual($property_views_data['user_id']['relationship']['base'], 'users');
+        $this->assertEqual($property_views_data['user_id']['relationship']['base field'], 'uid');
+        $this->assertEqual($property_views_data['user_id']['sort']['id'], 'standard');
+      }
+
+      if (isset($features['revision'])) {
+        $revision_views_data = $views_data_cache->get($features['revision']);
+
+        // Tests the join definition between the base and the revision table.
+        $this->assertEqual($revision_views_data['table']['join'][$features['base']], array(
+          'left_field' => 'id',
+          'field' => 'id',
+        ));
+
+        // Tests the revision data table views fields.
+        $this->assertEqual($revision_views_data['revision_id']['field']['id'], 'numeric');
+        $this->assertEqual($revision_views_data['revision_id']['filter']['id'], 'numeric');
+        $this->assertEqual($revision_views_data['revision_id']['argument']['id'], 'numeric');
+        $this->assertEqual($revision_views_data['revision_id']['sort']['id'], 'standard');
+
+        $this->assertEqual($revision_views_data['default_langcode']['field']['id'], 'boolean');
+        $this->assertEqual($revision_views_data['default_langcode']['filter']['id'], 'boolean');
+        $this->assertEqual($revision_views_data['default_langcode']['argument']['id'], 'numeric');
+        $this->assertEqual($revision_views_data['default_langcode']['sort']['id'], 'standard');
+
+        $this->assertEqual($revision_views_data['name']['field']['id'], 'standard');
+        $this->assertEqual($revision_views_data['name']['filter']['id'], 'string');
+        $this->assertEqual($revision_views_data['name']['argument']['id'], 'string');
+        $this->assertEqual($revision_views_data['name']['sort']['id'], 'standard');
+
+        $this->assertEqual($revision_views_data['user_id']['field']['id'], 'numeric');
+        $this->assertEqual($revision_views_data['user_id']['filter']['id'], 'numeric');
+        $this->assertEqual($revision_views_data['user_id']['argument']['id'], 'numeric');
+        $this->assertEqual($revision_views_data['user_id']['relationship']['id'], 'standard');
+        $this->assertEqual($revision_views_data['user_id']['relationship']['base'], 'users');
+        $this->assertEqual($revision_views_data['user_id']['relationship']['base field'], 'uid');
+        $this->assertEqual($revision_views_data['user_id']['sort']['id'], 'standard');
+      }
+    }
+  }
+
+  /**
+   * @todo
+   * Test an actual running view.
+   */
+}
diff --git a/core/modules/views/tests/Drupal/views/Tests/EntityViewsControllerTest.php b/core/modules/views/tests/Drupal/views/Tests/EntityViewsControllerTest.php
new file mode 100644
index 0000000..d5fa31f
--- /dev/null
+++ b/core/modules/views/tests/Drupal/views/Tests/EntityViewsControllerTest.php
@@ -0,0 +1,51 @@
+<?php
+//
+///**
+// * @file
+// * Contains \Drupal\views\Tests\EntityViewsControllerTest.
+// */
+//
+//namespace Drupal\views\Tests;
+//
+//use Drupal\Tests\UnitTestCase;
+//use Drupal\views\EntityViewsController;
+//
+///**
+// * Tests the generic entity views controller.
+// *
+// * @see \Drupal\views\EntityViewsController
+// */
+//class EntityViewsControllerTest extends UnitTestCase {
+//
+//  /**
+//   * Test base tables.
+//   */
+//  public function testBaseTables() {
+//    $storage = $this->getMockBuilder('Drupal\Core\Entity\DatabaseStorageControllerNG')
+//      ->disableOriginalConstructor()
+//      ->getMock();
+//    $entity_manager = $this->getMockBuilder('Drupal\Core\Entity\EntityManager')
+//      ->disableOriginalConstructor()
+//      ->getMock();
+//
+//    $entity_manager->expects($this->any())
+//      ->method('getDefinition')
+//      ->with($this->equalTo('entity_test'))
+//      ->will($this->returnValue(array(
+//        'id' => 'entity_test',
+//        'base_table' => 'entity_test',
+//        'label' => 'Test entity',
+//        'entity_keys' => array(
+//          'id' => 'id',
+//          'uuid' => 'uuid',
+//          'bundle' => 'type',
+//        ),
+//      )));
+//
+//    $views_controller = new EntityViewsController('entity_test', $storage, $entity_manager);
+//
+//    $data = $views_controller->viewsData();
+//    $this->assertEquals('id', $data['base']['base']['field']);
+//  }
+//
+//}
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index f8f9ff5..b1c27d4 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -928,6 +928,26 @@ function views_get_enabled_display_extenders() {
 }
 
 /**
+ * Gets the entity views controller class for an entity type.
+ *
+ * @param string $entity_type
+ *   Entity type for this views controller instance.
+ *
+ * @return \Drupal\views\EntityViewsControllerInterface
+ */
+function views_entity_get_views_controller($entity_type) {
+  $controllers = &drupal_static(__FUNCTION__, array());
+  if (!isset($controllers[$entity_type])) {
+    $entity_manager = \Drupal::entityManager();
+    $type_info = $entity_manager->getDefinition($entity_type);
+    $class = $type_info['controllers']['views'];
+    $storage_controller = $entity_manager->getStorageController($entity_type);
+    $controllers[$entity_type] = new $class($entity_type, $type_info, $storage_controller, $entity_manager);
+  }
+  return $controllers[$entity_type];
+}
+
+/**
  * Return a list of all views and display IDs that have a particular
  * setting in their display's plugin settings.
  *
diff --git a/core/modules/views/views.views.inc b/core/modules/views/views.views.inc
index 9b49b92..c820833 100644
--- a/core/modules/views/views.views.inc
+++ b/core/modules/views/views.views.inc
@@ -114,8 +114,9 @@ function views_views_data() {
     ),
   );
 
+
   // Registers an entity area handler per entity type.
-  foreach (entity_get_info() as $entity_type => $entity_info) {
+  foreach (\Drupal::entityManager()->getDefinitions() as $entity_type => $entity_info) {
     // Exclude entity types, which cannot be rendered.
     if (!empty($entity_info['controllers']['render'])) {
       $label = $entity_info['label'];
@@ -128,6 +129,12 @@ function views_views_data() {
         ),
       );
     }
+
+    // Execute the views controller for each entity type.
+    if (isset($entity_info['views_controller_class'])) {
+      $views_controller = views_entity_get_views_controller($entity_type);
+      $data += $views_controller->viewsData();
+    }
   }
 
   return $data;
