diff --git a/core/modules/forum/src/Tests/ForumTest.php b/core/modules/forum/src/Tests/ForumTest.php
index e1d6749..399673d 100644
--- a/core/modules/forum/src/Tests/ForumTest.php
+++ b/core/modules/forum/src/Tests/ForumTest.php
@@ -382,7 +382,7 @@ function createForum($type, $parent = 0) {
     );
 
     // Verify forum.
-    $term = db_query("SELECT * FROM {taxonomy_term_data} t WHERE t.vid = :vid AND t.name = :name AND t.description__value = :desc", array(':vid' => \Drupal::config('forum.settings')->get('vocabulary'), ':name' => $name, ':desc' => $description))->fetchAssoc();
+    $term = db_query("SELECT * FROM {taxonomy_term_field_data} t WHERE t.vid = :vid AND t.name = :name AND t.description__value = :desc AND t.default_langcode = 1", array(':vid' => \Drupal::config('forum.settings')->get('vocabulary'), ':name' => $name, ':desc' => $description))->fetchAssoc();
     $this->assertTrue(!empty($term), 'The ' . $type . ' exists in the database');
 
     // Verify forum hierarchy.
diff --git a/core/modules/node/src/Plugin/views/wizard/Node.php b/core/modules/node/src/Plugin/views/wizard/Node.php
index 377a6c6..0a18ea7 100644
--- a/core/modules/node/src/Plugin/views/wizard/Node.php
+++ b/core/modules/node/src/Plugin/views/wizard/Node.php
@@ -242,11 +242,12 @@ protected function buildFilters(&$form, FormStateInterface $form_state) {
     // Add the "tagged with" filter to the view.
 
     // We construct this filter using taxonomy_index.tid (which limits the
-    // filtering to a specific vocabulary) rather than taxonomy_term_data.name
-    // (which matches terms in any vocabulary). This is because it is a more
-    // commonly-used filter that works better with the autocomplete UI, and
-    // also to avoid confusion with other vocabularies on the site that may
-    // have terms with the same name but are not used for free tagging.
+    // filtering to a specific vocabulary) rather than
+    // taxonomy_term_field_data.name (which matches terms in any vocabulary).
+    // This is because it is a more commonly-used filter that works better with
+    // the autocomplete UI, and also to avoid confusion with other vocabularies
+    // on the site that may have terms with the same name but are not used for
+    // free tagging.
 
     // The downside is that if there *is* more than one vocabulary on the site
     // that is used for free tagging, the wizard will only be able to make the
diff --git a/core/modules/node/src/Tests/NodeAccessBaseTableTest.php b/core/modules/node/src/Tests/NodeAccessBaseTableTest.php
index 0a008e1..5452a00 100644
--- a/core/modules/node/src/Tests/NodeAccessBaseTableTest.php
+++ b/core/modules/node/src/Tests/NodeAccessBaseTableTest.php
@@ -90,8 +90,8 @@ function testNodeAccessBasic() {
         $this->nodesByUser[$this->webUser->id()][$node->id()] = $is_private;
       }
     }
-    $this->publicTid = db_query('SELECT tid FROM {taxonomy_term_data} WHERE name = :name', array(':name' => 'public'))->fetchField();
-    $this->privateTid = db_query('SELECT tid FROM {taxonomy_term_data} WHERE name = :name', array(':name' => 'private'))->fetchField();
+    $this->publicTid = db_query('SELECT tid FROM {taxonomy_term_field_data} WHERE name = :name AND default_langcode = 1', array(':name' => 'public'))->fetchField();
+    $this->privateTid = db_query('SELECT tid FROM {taxonomy_term_field_data} WHERE name = :name AND default_langcode = 1', array(':name' => 'private'))->fetchField();
     $this->assertTrue($this->publicTid, 'Public tid was found');
     $this->assertTrue($this->privateTid, 'Private tid was found');
     foreach ($simple_users as $this->webUser) {
diff --git a/core/modules/path/src/Tests/PathTaxonomyTermTest.php b/core/modules/path/src/Tests/PathTaxonomyTermTest.php
index c7ae9d3..b491324 100644
--- a/core/modules/path/src/Tests/PathTaxonomyTermTest.php
+++ b/core/modules/path/src/Tests/PathTaxonomyTermTest.php
@@ -49,7 +49,7 @@ function testTermAlias() {
       'path[0][alias]' => $this->randomName(),
     );
     $this->drupalPostForm('admin/structure/taxonomy/manage/' . $vocabulary->id() . '/add', $edit, t('Save'));
-    $tid = db_query("SELECT tid FROM {taxonomy_term_data} WHERE name = :name", array(':name' => $edit['name[0][value]']))->fetchField();
+    $tid = db_query("SELECT tid FROM {taxonomy_term_field_data} WHERE name = :name AND default_langcode = 1", array(':name' => $edit['name[0][value]']))->fetchField();
 
     // Confirm that the alias works.
     $this->drupalGet($edit['path[0][alias]']);
diff --git a/core/modules/taxonomy/src/Entity/Term.php b/core/modules/taxonomy/src/Entity/Term.php
index 8796e83..6557171 100644
--- a/core/modules/taxonomy/src/Entity/Term.php
+++ b/core/modules/taxonomy/src/Entity/Term.php
@@ -31,6 +31,7 @@
  *     "translation" = "Drupal\taxonomy\TermTranslationHandler"
  *   },
  *   base_table = "taxonomy_term_data",
+ *   data_table = "taxonomy_term_field_data",
  *   uri_callback = "taxonomy_term_uri",
  *   fieldable = TRUE,
  *   translatable = TRUE,
@@ -122,6 +123,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['name'] = FieldDefinition::create('string')
       ->setLabel(t('Name'))
       ->setDescription(t('The term name.'))
+      ->setTranslatable(TRUE)
       ->setRequired(TRUE)
       ->setSetting('max_length', 255)
       ->setDisplayOptions('view', array(
@@ -138,6 +140,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['description'] = FieldDefinition::create('text_long')
       ->setLabel(t('Description'))
       ->setDescription(t('A description of the term.'))
+      ->setTranslatable(TRUE)
       ->setSetting('text_processing', 1)
       ->setDisplayOptions('view', array(
         'label' => 'hidden',
diff --git a/core/modules/taxonomy/src/Plugin/views/argument/IndexTid.php b/core/modules/taxonomy/src/Plugin/views/argument/IndexTid.php
index 59b4332..3c59804 100644
--- a/core/modules/taxonomy/src/Plugin/views/argument/IndexTid.php
+++ b/core/modules/taxonomy/src/Plugin/views/argument/IndexTid.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\taxonomy\Plugin\views\argument;
 
+use Drupal\taxonomy\Entity\Term;
 use Drupal\views\Plugin\views\argument\ManyToOne;
 use Drupal\Component\Utility\String;
 
@@ -21,12 +22,9 @@ class IndexTid extends ManyToOne {
 
   public function titleQuery() {
     $titles = array();
-    $result = db_select('taxonomy_term_data', 'td')
-      ->fields('td', array('name'))
-      ->condition('td.tid', $this->value)
-      ->execute();
-    foreach ($result as $term_record) {
-      $titles[] = String::checkPlain($term_record->name);
+    $terms = Term::loadMultiple($this->value);
+    foreach ($terms as $term) {
+      $titles[] = String::checkPlain(\Drupal::entityManager()->getTranslationFromContext($term)->label());
     }
     return $titles;
   }
diff --git a/core/modules/taxonomy/src/Plugin/views/field/Language.php b/core/modules/taxonomy/src/Plugin/views/field/Language.php
index 13e3d23..f95f492 100644
--- a/core/modules/taxonomy/src/Plugin/views/field/Language.php
+++ b/core/modules/taxonomy/src/Plugin/views/field/Language.php
@@ -21,7 +21,7 @@ class Language extends Taxonomy {
    */
   public function render(ResultRow $values) {
     $value = $this->getValue($values);
-    $language = language_load($value);
+    $language = \Drupal::languageManager()->getLanguage($value);
     $value = $language ? $language->name : '';
 
     return $this->renderLink($this->sanitizeValue($value), $values);
diff --git a/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php b/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php
index 5aac9e1..2bae2fe 100644
--- a/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php
+++ b/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php
@@ -103,29 +103,23 @@ public function preRender(&$values) {
     }
 
     if ($nids) {
-      $query = db_select('taxonomy_term_data', 'td');
-      $query->innerJoin('taxonomy_index', 'tn', 'td.tid = tn.tid');
-      $query->fields('td');
-      $query->addField('tn', 'nid', 'node_nid');
-      $query->orderby('td.weight');
-      $query->orderby('td.name');
-      $query->condition('tn.nid', $nids);
-      $query->addTag('term_access');
       $vocabs = array_filter($this->options['vids']);
-      if (!empty($this->options['limit']) && !empty($vocabs)) {
-        $query->condition('td.vid', $vocabs);
+      if (empty($this->options['limit'])) {
+        $vocabs = array();
       }
-      $result = $query->execute();
-
-      foreach ($result as $term_record) {
-        $this->items[$term_record->node_nid][$term_record->tid]['name'] = String::checkPlain($term_record->name);
-        $this->items[$term_record->node_nid][$term_record->tid]['tid'] = $term_record->tid;
-        $this->items[$term_record->node_nid][$term_record->tid]['vocabulary_vid'] = $term_record->vid;
-        $this->items[$term_record->node_nid][$term_record->tid]['vocabulary'] = String::checkPlain($vocabularies[$term_record->vid]->label());
-
-        if (!empty($this->options['link_to_taxonomy'])) {
-          $this->items[$term_record->node_nid][$term_record->tid]['make_link'] = TRUE;
-          $this->items[$term_record->node_nid][$term_record->tid]['path'] = 'taxonomy/term/' . $term_record->tid;
+      $result = \Drupal::entityManager()->getStorage('taxonomy_term')->getNodeTerms($nids, $vocabs);
+
+      foreach ($result as $node_nid => $data) {
+        foreach ($data as $tid => $term) {
+          $this->items[$node_nid][$tid]['name'] = \Drupal::entityManager()->getTranslationFromContext($term)->label();
+          $this->items[$node_nid][$tid]['tid'] = $tid;
+          $this->items[$node_nid][$tid]['vocabulary_vid'] = $term->getVocabularyId();
+          $this->items[$node_nid][$tid]['vocabulary'] = String::checkPlain($vocabularies[$term->getVocabularyId()]->label());
+
+          if (!empty($this->options['link_to_taxonomy'])) {
+            $this->items[$node_nid][$tid]['make_link'] = TRUE;
+            $this->items[$node_nid][$tid]['path'] = 'taxonomy/term/' . $tid;
+          }
         }
       }
     }
diff --git a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
index c8f2381..35c4c73 100644
--- a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
+++ b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php
@@ -8,9 +8,11 @@
 namespace Drupal\taxonomy\Plugin\views\filter;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\taxonomy\Entity\Term;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\filter\ManyToOne;
+use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Tags;
 
 /**
@@ -108,15 +110,12 @@ protected function valueForm(&$form, FormStateInterface $form_state) {
     if ($this->options['type'] == 'textfield') {
       $default = '';
       if ($this->value) {
-        $result = db_select('taxonomy_term_data', 'td')
-          ->fields('td')
-          ->condition('td.tid', $this->value)
-          ->execute();
-        foreach ($result as $term_record) {
+        $terms = Term::loadMultiple(($this->value));
+        foreach ($terms as $term) {
           if ($default) {
             $default .= ', ';
           }
-          $default .= $term_record->name;
+          $default .= String::checkPlain(\Drupal::entityManager()->getTranslationFromContext($term)->label());
         }
       }
 
@@ -133,31 +132,30 @@ protected function valueForm(&$form, FormStateInterface $form_state) {
     }
     else {
       if (!empty($this->options['hierarchy']) && $this->options['limit']) {
-        $tree = taxonomy_get_tree($vocabulary->id());
+        $tree = taxonomy_get_tree($vocabulary->id(), 0, NULL, TRUE);
         $options = array();
 
         if ($tree) {
-          foreach ($tree as $term_record) {
+          foreach ($tree as $term) {
             $choice = new \stdClass();
-            $choice->option = array($term_record->tid => str_repeat('-', $term_record->depth) . $term_record->name);
+            $choice->option = array($term->id() => str_repeat('-', $term->depth) . String::checkPlain(\Drupal::entityManager()->getTranslationFromContext($term)->label()));
             $options[] = $choice;
           }
         }
       }
       else {
         $options = array();
-        $query = db_select('taxonomy_term_data', 'td');
-        $query->fields('td');
-        // @todo Sorting on vocabulary properties http://drupal.org/node/1821274
-        $query->orderby('td.weight');
-        $query->orderby('td.name');
-        $query->addTag('term_access');
+        $query = \Drupal::entityQuery('taxonomy_term')
+          // @todo Sorting on vocabulary properties http://drupal.org/node/1821274
+          ->sort('weight')
+          ->sort('name')
+          ->addTag('term_access');
         if ($this->options['limit']) {
-          $query->condition('td.vid', $vocabulary->id());
+          $query->condition('vid', $vocabulary->id());
         }
-        $result = $query->execute();
-        foreach ($result as $term_record) {
-          $options[$term_record->tid] = $term_record->name;
+        $terms = Term::loadMultiple($query->execute());
+        foreach ($terms as $term) {
+          $options[$term->id()] = String::checkPlain(\Drupal::entityManager()->getTranslationFromContext($term)->label());
         }
       }
 
@@ -220,7 +218,7 @@ protected function valueValidate($form, FormStateInterface $form_state) {
     }
 
     $values = Tags::explode($form_state['values']['options']['value']);
-    $tids = $this->validate_term_strings($form['value'], $values);
+    $tids = $this->validate_term_strings($form['value'], $values, $form_state);
 
     if ($tids) {
       $form_state['values']['options']['value'] = $tids;
@@ -275,7 +273,7 @@ public function validateExposed(&$form, FormStateInterface $form_state) {
 
     $values = Tags::explode($form_state['values'][$identifier]);
 
-    $tids = $this->validate_term_strings($form[$identifier], $values);
+    $tids = $this->validate_term_strings($form[$identifier], $values, $form_state);
     if ($tids) {
       $this->validated_exposed_input = $tids;
     }
@@ -290,11 +288,13 @@ public function validateExposed(&$form, FormStateInterface $form_state) {
    *   The form which is used, either the views ui or the exposed filters.
    * @param $values
    *   The taxonomy names which will be converted to tids.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
    *
    * @return array
    *   The taxonomy ids fo all validated terms.
    */
-  function validate_term_strings(&$form, $values) {
+  function validate_term_strings(&$form, $values, FormStateInterface $form_state) {
     if (empty($values)) {
       return array();
     }
@@ -311,15 +311,14 @@ function validate_term_strings(&$form, $values) {
       return FALSE;
     }
 
-    $query = db_select('taxonomy_term_data', 'td');
-    $query->fields('td');
-    $query->condition('td.name', $names);
-    $query->condition('td.vid', $this->options['vid']);
-    $query->addTag('term_access');
-    $result = $query->execute();
-    foreach ($result as $term_record) {
-      unset($missing[strtolower($term_record->name)]);
-      $tids[] = $term_record->tid;
+    $query = \Drupal::entityQuery('taxonomy_term')
+      ->condition('name', $names)
+      ->condition('vid', $this->options['vid'])
+      ->addTag('term_access');
+    $terms = Term::loadMultiple($query->execute());
+    foreach ($terms as $term) {
+      unset($missing[strtolower(\Drupal::entityManager()->getTranslationFromContext($term)->label())]);
+      $tids[] = $term->id();
     }
 
     if ($missing && !empty($this->options['error_message'])) {
@@ -354,12 +353,9 @@ public function adminSummary() {
 
     if ($this->value) {
       $this->value = array_filter($this->value);
-      $result = db_select('taxonomy_term_data', 'td')
-        ->fields('td')
-        ->condition('td.tid', $this->value)
-        ->execute();
-      foreach ($result as $term_record) {
-        $this->value_options[$term_record->tid] = $term_record->name;
+      $terms = Term::loadMultiple($this->value);
+      foreach ($terms as $term) {
+        $this->value_options[$term->id()] = String::checkPlain(\Drupal::entityManager()->getTranslationFromContext($term)->label());
       }
     }
     return parent::adminSummary();
diff --git a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTidDepth.php b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTidDepth.php
index cb30f46..eb93480 100644
--- a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTidDepth.php
+++ b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTidDepth.php
@@ -52,7 +52,7 @@ public function query() {
       return;
     }
     elseif (count($this->value) == 1) {
-      // Somethis $this->value is an array with a single element so convert it.
+      // Sometimes $this->value is an array with a single element so convert it.
       if (is_array($this->value)) {
         $this->value = current($this->value);
       }
diff --git a/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php b/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php
index 3483093..8b79ce2 100644
--- a/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php
+++ b/core/modules/taxonomy/src/Plugin/views/relationship/NodeTermData.php
@@ -56,7 +56,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
       '#type' => 'checkboxes',
       '#title' => t('Vocabularies'),
       '#options' => $options,
-      '#default_value' => $this->options['vocabularies'],
+      '#default_value' => $this->options['vids'],
       '#description' => t('Choose which vocabularies you wish to relate. Remember that every term found will create a new record, so this relationship is best used on just one vocabulary that has only one term per node.'),
     );
     parent::buildOptionsForm($form, $form_state);
diff --git a/core/modules/taxonomy/src/Plugin/views/wizard/TaxonomyTerm.php b/core/modules/taxonomy/src/Plugin/views/wizard/TaxonomyTerm.php
index 1c34511..480dc26 100644
--- a/core/modules/taxonomy/src/Plugin/views/wizard/TaxonomyTerm.php
+++ b/core/modules/taxonomy/src/Plugin/views/wizard/TaxonomyTerm.php
@@ -49,7 +49,7 @@ protected function defaultDisplayOptions() {
 
     /* Field: Taxonomy: Term */
     $display_options['fields']['name']['id'] = 'name';
-    $display_options['fields']['name']['table'] = 'taxonomy_term_data';
+    $display_options['fields']['name']['table'] = 'taxonomy_term_field_data';
     $display_options['fields']['name']['field'] = 'name';
     $display_options['fields']['name']['provider'] = 'taxonomy';
     $display_options['fields']['name']['label'] = '';
diff --git a/core/modules/taxonomy/src/TermStorage.php b/core/modules/taxonomy/src/TermStorage.php
index 381b0ab..345921c 100644
--- a/core/modules/taxonomy/src/TermStorage.php
+++ b/core/modules/taxonomy/src/TermStorage.php
@@ -7,10 +7,9 @@
 
 namespace Drupal\taxonomy;
 
+use Drupal\Core\Entity\ContentEntityDatabaseStorage;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\Query\QueryInterface;
-use Drupal\Core\Entity\ContentEntityDatabaseStorage;
 
 /**
  * Defines a Controller class for taxonomy terms.
@@ -87,10 +86,11 @@ public function updateTermHierarchy(EntityInterface $term) {
    * {@inheritdoc}
    */
   public function loadParents($tid) {
-    $query = $this->database->select('taxonomy_term_data', 't');
+    $query = $this->database->select('taxonomy_term_field_data', 't');
     $query->join('taxonomy_term_hierarchy', 'h', 'h.parent = t.tid');
     $query->addField('t', 'tid');
     $query->condition('h.tid', $tid);
+    $query->condition('t.default_langcode', 1);
     $query->addTag('term_access');
     $query->orderBy('t.weight');
     $query->orderBy('t.name');
@@ -101,13 +101,14 @@ public function loadParents($tid) {
    * {@inheritdoc}
    */
   public function loadChildren($tid, $vid = NULL) {
-    $query = $this->database->select('taxonomy_term_data', 't');
+    $query = $this->database->select('taxonomy_term_field_data', 't');
     $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
     $query->addField('t', 'tid');
     $query->condition('h.parent', $tid);
     if ($vid) {
       $query->condition('t.vid', $vid);
     }
+    $query->condition('t.default_langcode', 1);
     $query->addTag('term_access');
     $query->orderBy('t.weight');
     $query->orderBy('t.name');
@@ -118,13 +119,14 @@ public function loadChildren($tid, $vid = NULL) {
    * {@inheritdoc}
    */
   public function loadTree($vid) {
-    $query = $this->database->select('taxonomy_term_data', 't');
+    $query = $this->database->select('taxonomy_term_field_data', 't');
     $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
     return $query
       ->addTag('term_access')
       ->fields('t')
       ->fields('h', array('parent'))
       ->condition('t.vid', $vid)
+      ->condition('t.default_langcode', 1)
       ->orderBy('t.weight')
       ->orderBy('t.name')
       ->execute();
@@ -146,7 +148,7 @@ public function nodeCount($vid) {
    * {@inheritdoc}
    */
   public function resetWeights($vid) {
-    $this->database->update('taxonomy_term_data')
+    $this->database->update('taxonomy_term_field_data')
       ->fields(array('weight' => 0))
       ->condition('vid', $vid)
       ->execute();
@@ -160,12 +162,12 @@ public function getSchema() {
 
     // Marking the respective fields as NOT NULL makes the indexes more
     // performant.
-    $schema['taxonomy_term_data']['fields']['weight']['not null'] = TRUE;
-    $schema['taxonomy_term_data']['fields']['name']['not null'] = TRUE;
+    $schema['taxonomy_term_field_data']['fields']['weight']['not null'] = TRUE;
+    $schema['taxonomy_term_field_data']['fields']['name']['not null'] = TRUE;
 
-    unset($schema['taxonomy_term_data']['indexes']['field__vid']);
-    unset($schema['taxonomy_term_data']['indexes']['field__description__format']);
-    $schema['taxonomy_term_data']['indexes'] += array(
+    unset($schema['taxonomy_term_field_data']['indexes']['taxonomy_term_field__vid__target_id']);
+    unset($schema['taxonomy_term_field_data']['indexes']['taxonomy_term_field__description__format']);
+    $schema['taxonomy_term_field_data']['indexes'] += array(
       'taxonomy_term__tree' => array('vid', 'weight', 'name'),
       'taxonomy_term__vid_name' => array('vid', 'name'),
       'taxonomy_term__name' => array('name'),
@@ -251,4 +253,39 @@ public function getSchema() {
     return $schema;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getNodeTerms($nids, $vocabs = array(), $langcode = NULL) {
+    $query = db_select('taxonomy_term_field_data', 'td');
+    $query->innerJoin('taxonomy_index', 'tn', 'td.tid = tn.tid');
+    $query->fields('td', array('tid'));
+    $query->addField('tn', 'nid', 'node_nid');
+    $query->orderby('td.weight');
+    $query->orderby('td.name');
+    $query->condition('tn.nid', $nids);
+    $query->addTag('term_access');
+    if (!empty($vocabs)) {
+      $query->condition('td.vid', $vocabs);
+    }
+    if (!empty($langcode)) {
+      $query->condition('td.langcode', $langcode);
+    }
+
+    $results = array();
+    foreach ($query->execute() as $term_record) {
+      $results[$term_record->node_nid][] = $term_record->tid;
+      $all_tids[] = $term_record->tid;
+    }
+
+    $all_terms = $this->loadMultiple($all_tids);
+    $terms = array();
+    foreach ($results as $nid => $tids) {
+      foreach ($tids as $tid) {
+        $terms[$nid][$tid] = $all_terms[$term_record->tid];
+      }
+    }
+    return $terms;
+  }
+
 }
diff --git a/core/modules/taxonomy/src/TermStorageInterface.php b/core/modules/taxonomy/src/TermStorageInterface.php
index 634ff3d..f450db0 100644
--- a/core/modules/taxonomy/src/TermStorageInterface.php
+++ b/core/modules/taxonomy/src/TermStorageInterface.php
@@ -85,4 +85,20 @@ public function nodeCount($vid);
    */
   public function resetWeights($vid);
 
+  /**
+   * Returns all terms used to tag some given nodes.
+   *
+   * @param array $nids
+   *   Node IDs to retrieve terms for.
+   * @param array $vocabs
+   *   (optional) A vocabularies array to restrict the term search. Defaults to
+   *   empty array.
+   * @param string $langcode
+   *   (optional) A language code to restrict the term search. Defaults to NULL.
+   *
+   * @return array
+   *   An array of nids and the term entities they were tagged with.
+   */
+  public function getNodeTerms($nids, $vocabs = array(), $langcode = NULL);
+
 }
diff --git a/core/modules/taxonomy/src/Tests/TermTranslationUITest.php b/core/modules/taxonomy/src/Tests/TermTranslationUITest.php
index e0d3271..dddabdd 100644
--- a/core/modules/taxonomy/src/Tests/TermTranslationUITest.php
+++ b/core/modules/taxonomy/src/Tests/TermTranslationUITest.php
@@ -18,11 +18,6 @@
 class TermTranslationUITest extends ContentTranslationUITest {
 
   /**
-   * The name of the test taxonomy term.
-   */
-  protected $name;
-
-  /**
    * The vocabulary used for creating terms.
    *
    * @var \Drupal\taxonomy\Entity\Vocabulary
@@ -39,7 +34,6 @@ class TermTranslationUITest extends ContentTranslationUITest {
   function setUp() {
     $this->entityTypeId = 'taxonomy_term';
     $this->bundle = 'tags';
-    $this->name = $this->randomName();
     parent::setUp();
   }
 
@@ -71,8 +65,7 @@ protected function getTranslatorPermissions() {
    * Overrides \Drupal\content_translation\Tests\ContentTranslationUITest::getNewEntityValues().
    */
   protected function getNewEntityValues($langcode) {
-    // Term name is not translatable hence we use a fixed value.
-    return array('name' => $this->name) + parent::getNewEntityValues($langcode);
+    return array('name' => $this->randomName()) + parent::getNewEntityValues($langcode);
   }
 
   /**
diff --git a/core/modules/taxonomy/src/Tests/Views/RelationshipNodeTermDataTest.php b/core/modules/taxonomy/src/Tests/Views/RelationshipNodeTermDataTest.php
index 478eff0..930990f 100644
--- a/core/modules/taxonomy/src/Tests/Views/RelationshipNodeTermDataTest.php
+++ b/core/modules/taxonomy/src/Tests/Views/RelationshipNodeTermDataTest.php
@@ -26,16 +26,25 @@ class RelationshipNodeTermDataTest extends TaxonomyTestBase {
   function testViewsHandlerRelationshipNodeTermData() {
     $view = Views::getView('test_taxonomy_node_term_data');
     $this->executeView($view, array($this->term1->id(), $this->term2->id()));
-    $resultset = array(
+    $expected_result = array(
       array(
-        'nid' => $this->nodes[0]->id(),
+        'nid' => $this->nodes[1]->id(),
       ),
       array(
-        'nid' => $this->nodes[1]->id(),
+        'nid' => $this->nodes[0]->id(),
       ),
     );
-    $this->column_map = array('nid' => 'nid');
-    $this->assertIdenticalResultset($view, $resultset, $this->column_map);
+    $column_map = array('nid' => 'nid');
+    $this->assertIdenticalResultset($view, $expected_result, $column_map);
+
+    // Change the view to test relation limited by vocabulary.
+    \Drupal::config('views.view.test_taxonomy_node_term_data')
+      ->set('display.default.display_options.relationships.term_node_tid.vids.tags', 'views_testing_tags')
+      ->save();
+
+    $view = Views::getView('test_taxonomy_node_term_data');
+    $this->executeView($view, array($this->term1->id(), $this->term2->id()));
+    $this->assertIdenticalResultset($view, $expected_result, $column_map);
   }
 
 }
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 61ecb8b..3058dc3 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -456,9 +456,9 @@ function taxonomy_term_load_children($tid) {
  *   The number of levels of the tree to return. Leave NULL to return all levels.
  * @param $load_entities
  *   If TRUE, a full entity load will occur on the term objects. Otherwise they
- *   are partial objects queried directly from the {taxonomy_term_data} table to
- *   save execution time and memory consumption when listing large numbers of
- *   terms. Defaults to FALSE.
+ *   are partial objects queried directly from the {taxonomy_term_field_data}
+ *   table to save execution time and memory consumption when listing large
+ *   numbers of terms. Defaults to FALSE.
  *
  * @return
  *   An array of all term objects in the tree. Each term object is extended
diff --git a/core/modules/taxonomy/taxonomy.views.inc b/core/modules/taxonomy/taxonomy.views.inc
index fa34f4f..3f9793b 100644
--- a/core/modules/taxonomy/taxonomy.views.inc
+++ b/core/modules/taxonomy/taxonomy.views.inc
@@ -32,6 +32,14 @@ function taxonomy_views_data() {
     ),
   );
 
+  $data['taxonomy_term_field_data']['table']['group'] = t('Taxonomy term');
+  $data['taxonomy_term_field_data']['table']['entity type'] = 'taxonomy_term';
+  $data['taxonomy_term_field_data']['table']['join']['taxonomy_term_data'] = array(
+    'type' => 'INNER',
+    'left_field' => 'tid',
+    'field' => 'tid',
+  );
+
   $data['taxonomy_term_data']['tid'] = array(
     'title' => t('Term ID'),
     'help' => t('The tid of a taxonomy term.'),
@@ -73,7 +81,7 @@ function taxonomy_views_data() {
       'id' => 'groupwise_max',
       'relationship field' => 'tid',
       'outer field' => 'taxonomy_term_data.tid',
-      'argument table' => 'taxonomy_term_data',
+      'argument table' => 'taxonomy_term_field_data',
       'argument field' =>  'tid',
       'base'   => 'node',
       'field'  => 'nid',
@@ -81,7 +89,7 @@ function taxonomy_views_data() {
     ),
   );
 
-  $data['taxonomy_term_data']['name'] = array(
+  $data['taxonomy_term_field_data']['name'] = array(
     'title' => t('Name'),
     'help' => t('The taxonomy term name.'),
     'field' => array(
@@ -102,7 +110,7 @@ function taxonomy_views_data() {
     ),
   );
 
-  $data['taxonomy_term_data']['weight'] = array(
+  $data['taxonomy_term_field_data']['weight'] = array(
     'title' => t('Weight'),
     'help' => t('The term weight field'),
     'field' => array(
@@ -119,7 +127,7 @@ function taxonomy_views_data() {
     ),
   );
 
-  $data['taxonomy_term_data']['description__value'] = array(
+  $data['taxonomy_term_field_data']['description__value'] = array(
     'title' => t('Term description'),
     'help' => t('The description associated with a taxonomy term.'),
     'field' => array(
@@ -140,7 +148,7 @@ function taxonomy_views_data() {
     ),
   );
 
-  $data['taxonomy_term_data']['langcode'] = array(
+  $data['taxonomy_term_field_data']['langcode'] = array(
     'title' => t('Language'), // The item it appears as on the UI,
     'help' => t('Language of the term'),
     'field' => array(
@@ -166,7 +174,7 @@ function taxonomy_views_data() {
     ),
   );
 
-  $data['taxonomy_term_data']['changed'] = array(
+  $data['taxonomy_term_field_data']['changed'] = array(
     'title' => t('Updated date'),
     'help' => t('The date the term was last updated.'),
     'field' => array(
@@ -180,7 +188,7 @@ function taxonomy_views_data() {
     ),
   );
 
-  $data['taxonomy_term_data']['changed_fulldate'] = array(
+  $data['taxonomy_term_field_data']['changed_fulldate'] = array(
     'title' => t('Updated date'),
     'help' => t('Date in the form of CCYYMMDD.'),
     'argument' => array(
@@ -189,7 +197,7 @@ function taxonomy_views_data() {
     ),
   );
 
-  $data['taxonomy_term_data']['changed_year_month'] = array(
+  $data['taxonomy_term_field_data']['changed_year_month'] = array(
     'title' => t('Updated year + month'),
     'help' => t('Date in the form of YYYYMM.'),
     'argument' => array(
@@ -198,7 +206,7 @@ function taxonomy_views_data() {
     ),
   );
 
-  $data['taxonomy_term_data']['changed_year'] = array(
+  $data['taxonomy_term_field_data']['changed_year'] = array(
     'title' => t('Updated year'),
     'help' => t('Date in the form of YYYY.'),
     'argument' => array(
@@ -207,7 +215,7 @@ function taxonomy_views_data() {
     ),
   );
 
-  $data['taxonomy_term_data']['changed_month'] = array(
+  $data['taxonomy_term_field_data']['changed_month'] = array(
     'title' => t('Updated month'),
     'help' => t('Date in the form of MM (01 - 12).'),
     'argument' => array(
@@ -216,7 +224,7 @@ function taxonomy_views_data() {
     ),
   );
 
-  $data['taxonomy_term_data']['changed_day'] = array(
+  $data['taxonomy_term_field_data']['changed_day'] = array(
     'title' => t('Updated day'),
     'help' => t('Date in the form of DD (01 - 31).'),
     'argument' => array(
@@ -225,7 +233,7 @@ function taxonomy_views_data() {
     ),
   );
 
-  $data['taxonomy_term_data']['changed_week'] = array(
+  $data['taxonomy_term_field_data']['changed_week'] = array(
     'title' => t('Updated week'),
     'help' => t('Date in the form of WW (01 - 53).'),
     'argument' => array(
@@ -283,7 +291,7 @@ function taxonomy_views_data() {
     'help' => t('Display content if it has the selected taxonomy terms.'),
     'argument' => array(
       'id' => 'taxonomy_index_tid',
-      'name table' => 'taxonomy_term_data',
+      'name table' => 'taxonomy_term_field_data',
       'name field' => 'name',
       'empty field name' => t('Uncategorized'),
       'numeric' => TRUE,
diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_groupwise_term.yml b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_groupwise_term.yml
index 5fd37bc..fa61b8b 100644
--- a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_groupwise_term.yml
+++ b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_groupwise_term.yml
@@ -16,7 +16,7 @@ display:
         name:
           field: name
           id: name
-          table: taxonomy_term_data
+          table: taxonomy_term_field_data
           plugin_id: taxonomy
           provider: taxonomy
         nid:
diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_taxonomy_node_term_data.yml b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_taxonomy_node_term_data.yml
index a3fc3ca..afdd91e 100644
--- a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_taxonomy_node_term_data.yml
+++ b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_taxonomy_node_term_data.yml
@@ -48,7 +48,7 @@ display:
           id: term_node_tid
           label: 'Term #1'
           table: node
-          vocabularies:
+          vids:
             tags: false
           plugin_id: node_term_data
           provider: taxonomy
@@ -57,7 +57,7 @@ display:
           id: term_node_tid_1
           label: 'Term #2'
           table: node
-          vocabularies:
+          vids:
             tags: false
           plugin_id: node_term_data
           provider: taxonomy
@@ -66,7 +66,7 @@ display:
           field: nid
           id: nid
           order: DESC
-          table: nid
+          table: node
           plugin_id: standard
           provider: views
       style:
