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..3c1f08d
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/EntityViewsController.php
@@ -0,0 +1,198 @@
+<?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, EntityStorageControllerInterface $storage_controller, EntityManager $entity_manager) {
+    $this->entityType = $entity_type;
+    $this->entityInfo = $entity_manager->getDefinition($entity_type);
+    $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,
+      $container->get('plugin.manager.entity')->getStorageController($entity_type),
+      $container->get('plugin.manager.entity')
+    );
+  }
+
+  /**
+   * {@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);
+
+    // Integration the base_table within views.
+    foreach ($this->entityInfo['base_table'] as $field) {
+      $typed_data = $field_definitions[$field];
+
+      $views_field = &$data[$base_table][$field];
+      // @todo Is translating the right way to handle label/description?
+      $views_field['title'] = t($typed_data['label']);
+      $views_field['help'] = t($typed_data['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($typed_data, $views_field);
+    }
+
+    // Integration the revision_table within views.
+    if ($revision_table) {
+      foreach ($this->entityInfo['revision_table'] as $field) {
+        $typed_data = $field_definitions[$field];
+
+        $views_field = &$data[$revision_table][$field];
+        // @todo Is translating the right way to handle label/description?
+        $views_field['title'] = t($typed_data['label']);
+        $views_field['help'] = t($typed_data['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($typed_data, $views_field);
+      }
+    }
+
+    return $data;
+  }
+
+  /**
+   * @todo
+   */
+  protected function mapTypedDataHandlerId($typed_data, $views_field) {
+    switch ($typed_data['type']) {
+      case 'integer_field':
+        $views_field['field']['id'] = 'numeric';
+        $views_field['argument']['id'] = 'numeric';
+        $views_field['filter']['id'] = 'numeric';
+        $views_field['sort']['id'] = 'standard';
+        break;
+      case 'string_field':
+        $views_field['field']['id'] = 'standard';
+        $views_field['argument']['id'] = 'string';
+        $views_field['filter']['id'] = 'string';
+        $views_field['sort']['id'] = 'standard';
+        break;
+      case 'language_field':
+        $views_field['field']['id'] = 'language';
+        $views_field['argument']['id'] = 'language';
+        $views_field['filter']['id'] = 'language';
+        $views_field['sort']['id'] = 'standard';
+        break;
+      case 'boolean_field':
+        $views_field['field']['id'] = 'boolean';
+        $views_field['argument']['id'] = 'numeric';
+        $views_field['filter']['id'] = 'boolean';
+        $views_field['sort']['id'] = 'standard';
+        break;
+      case'entityreference_field':
+        // @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']['entity 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..c2e4783
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Tests/EntityViewsControllerTest.php
@@ -0,0 +1,146 @@
+<?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('Test entity'), $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.
+        debug($revision_views_data);
+        $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..954e882
--- /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..64a845b 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -928,6 +928,25 @@ 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])) {
+    $type_info = entity_get_info($entity_type);
+    $class = $type_info['views_controller_class'];
+    $storage_controller = entity_get_controller($entity_type);
+    $controllers[$entity_type] = new $class($entity_type, $storage_controller);
+  }
+  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..7955dff 100644
--- a/core/modules/views/views.views.inc
+++ b/core/modules/views/views.views.inc
@@ -130,5 +130,13 @@ function views_views_data() {
     }
   }
 
+  // Execute the views controller for each entity type.
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    if (isset($entity_info['views_controller_class'])) {
+      $views_controller = views_entity_get_views_controller($entity_type);
+      $data += $views_controller->viewsData();
+    }
+  }
+
   return $data;
 }
