diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php
index 1c8979e..e0a1cf3 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php
@@ -24,6 +24,7 @@
  *     "default" = "Drupal\entity_test\EntityTestFormController"
  *   },
  *   translation_controller_class = "Drupal\translation_entity\EntityTranslationControllerNG",
+ *   views_controller_class = "Drupal\views\EntityViewsController",
  *   base_table = "entity_test",
  *   fieldable = TRUE,
  *   entity_keys = {
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php
index ec3119c..09cde45 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php
@@ -24,6 +24,7 @@
  *     "default" = "Drupal\entity_test\EntityTestFormController"
  *   },
  *   translation_controller_class = "Drupal\translation_entity\EntityTranslationControllerNG",
+ *   views_controller_class = "Drupal\views\EntityViewsController",
  *   base_table = "entity_test_mul",
  *   data_table = "entity_test_mul_property_data",
  *   fieldable = TRUE,
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php
index 714486a..2c635e9 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php
@@ -24,6 +24,7 @@
  *     "default" = "Drupal\entity_test\EntityTestFormController"
  *   },
  *   translation_controller_class = "Drupal\translation_entity\EntityTranslationControllerNG",
+ *   views_controller_class = "Drupal\views\EntityViewsController",
  *   base_table = "entity_test_mulrev",
  *   data_table = "entity_test_mulrev_property_data",
  *   revision_table = "entity_test_mulrev_property_revision",
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestRev.php
index 485b31d..72544ae 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestRev.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestRev.php
@@ -24,6 +24,7 @@
  *     "default" = "Drupal\entity_test\EntityTestFormController"
  *   },
  *   translation_controller_class = "Drupal\translation_entity\EntityTranslationControllerNG",
+ *   views_controller_class = "Drupal\views\EntityViewsController",
  *   base_table = "entity_test_rev",
  *   revision_table = "entity_test_rev_revision",
  *   fieldable = TRUE,
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..f5d1d1c
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/EntityViewsController.php
@@ -0,0 +1,180 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\EntityViewsController.
+ */
+
+namespace Drupal\views;
+
+/**
+ * Provides a generic views integration of entity-NG.
+ */
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+
+class EntityViewsController {
+  /**
+   * 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.
+   */
+  function __construct($entity_type, EntityStorageControllerInterface $storage_controller) {
+    $this->entityType = $entity_type;
+    $this->entityInfo = entity_get_info($entity_type);
+    $this->storageController = $storage_controller;
+  }
+
+  /**
+   * Implements \Drupal\entity\EntityViewsControllerInterface::viewsData().
+   */
+  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 = $this->entityInfo['entity_keys']['revision'];
+
+    // 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 base information of the views data.
+    $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'])),
+    );
+
+    // 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']['join'][$base_table] = array(
+        'left_field' => $base_field,
+        'field' => $base_field,
+      );
+    }
+
+    // Load all typed data definitions of all fields.
+    $field_definitions = $this->storageController->getFieldDefinitions(array('entity type' => $this->entityType));
+
+    // Integration the base_table within views.
+    foreach ($this->entityInfo['schema_fields_sql']['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['schema_fields_sql']['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 = entity_get_info($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..c98c32c
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Tests/EntityViewsControllerTest.php
@@ -0,0 +1,126 @@
+<?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() {
+    $views_data_cache = drupal_container()->get('views.views_data');
+    $views_data = $views_data_cache->get('entity_test');
+    debug($views_data);
+    $property_views_data = $views_data_cache->get('entity_test_property_data');
+    $revision_views_data = $views_data_cache->get('entity_test_property_revision');
+
+    $base_data = array(
+      'field' => 'id',
+      'title' => t('Test entity'),
+    );
+    $this->assertEqual($views_data['table']['base'], $base_data, 'The entity is registered as base table.');
+
+    // Tests the join definition between the base and the revision table.
+//    $this->assertEqual($revision_views_data['table']['join']['entity_test'], array(
+//      'left_field' => 'id',
+//      'field' => 'id',
+//    ));
+
+    // 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');
+
+//    // 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');
+//
+//    // 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/views.module b/core/modules/views/views.module
index 287e2e0..aa4f562 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -1111,6 +1111,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 3a145b2..7f72f25 100644
--- a/core/modules/views/views.views.inc
+++ b/core/modules/views/views.views.inc
@@ -106,5 +106,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;
 }
