diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d7_taxonomy_term.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d7_taxonomy_term.yml
new file mode 100755
index 0000000..19c2cb4
--- /dev/null
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d7_taxonomy_term.yml
@@ -0,0 +1,28 @@
+id: d7_taxonomy_term
+label: Drupal 7 taxonomy terms
+migration_tags:
+  - Drupal 7
+source:
+  plugin: d7_taxonomy_term
+process:
+  tid: tid
+  vid:
+    plugin: migration
+    migration: d7_taxonomy_vocabulary
+    source: vid
+  name: name
+  description: description
+  weight: weight
+  parent:
+    -
+      plugin: skip_process_on_empty
+      source: parent
+    -
+      plugin: migration
+      migration: d7_taxonomy_term
+  changed: timestamp
+destination:
+  plugin: entity:taxonomy_term
+migration_dependencies:
+  required:
+    - d7_taxonomy_vocabulary
diff --git a/core/modules/migrate_drupal/config/install/migrate.migration.d7_taxonomy_vocabulary.yml b/core/modules/migrate_drupal/config/install/migrate.migration.d7_taxonomy_vocabulary.yml
new file mode 100755
index 0000000..065c19a
--- /dev/null
+++ b/core/modules/migrate_drupal/config/install/migrate.migration.d7_taxonomy_vocabulary.yml
@@ -0,0 +1,23 @@
+id: d7_taxonomy_vocabulary
+label: Drupal 7 taxonomy vocabularies
+migration_tags:
+  - Drupal 7
+source:
+  plugin: d7_taxonomy_vocabulary
+process:
+  vid:
+    -
+      plugin: machine_name
+      source: machine_name
+    -
+      plugin: dedupe_entity
+      entity_type: taxonomy_vocabulary
+      field: vid
+      length: 32
+  label: name
+  name: name
+  description: description
+  hierarchy: hierarchy
+  weight: weight
+destination:
+  plugin: entity:taxonomy_vocabulary
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/Term.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/Term.php
new file mode 100755
index 0000000..157ec5b
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/Term.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Plugin\migrate\source\Term.
+ */
+
+namespace Drupal\migrate_drupal\Plugin\migrate\source\d7;
+
+use Drupal\migrate\Row;
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+
+/**
+ * Drupal 7 taxonomy terms source from database.
+ *
+ * @todo Support term_relation, term_synonym table if possible.
+ *
+ * @MigrateSource(
+ *   id = "d7_taxonomy_term",
+ *   source_provider = "taxonomy"
+ * )
+ */
+class Term extends DrupalSqlBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    // Note the explode - this supports the (admittedly unusual) case of
+    // consolidating multiple vocabularies into one.
+    $query = $this->select('taxonomy_term_data', 'td')
+      ->fields('td', array('tid', 'vid', 'name', 'description', 'weight', 'format'))
+    // This works, but we cannot test that, because there is no support for
+    // distinct() in FakeSelect, yet.
+      ->distinct();
+    if (isset($this->configuration['vocabulary'])) {
+      $query->condition('vid', $this->configuration['vocabulary'], 'IN');
+    }
+    return $query;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array(
+      'tid' => $this->t('The term ID.'),
+      'vid' => $this->t('Existing term VID'),
+      'name' => $this->t('The name of the term.'),
+      'description' => $this->t('The term description.'),
+      'weight' => $this->t('Weight'),
+      'parent' => $this->t("The Drupal term IDs of the term's parents."),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareRow(Row $row) {
+    // Find parents for this row.
+    $parents = $this->select('taxonomy_term_hierarchy', 'th')
+      ->fields('th', array('parent', 'tid'))
+      ->condition('tid', $row->getSourceProperty('tid'))
+      ->execute()
+      ->fetchCol();
+    $row->setSourceProperty('parent', $parents);
+    return parent::prepareRow($row);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['tid']['type'] = 'integer';
+    return $ids;
+  }
+
+}
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/Vocabulary.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/Vocabulary.php
new file mode 100755
index 0000000..929009e
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/Vocabulary.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_mtm\Plugin\migrate\source\Vocabulary.
+ */
+
+namespace Drupal\migrate_drupal\Plugin\migrate\source\d7;
+
+use Drupal\migrate\Row;
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+
+/**
+ * Drupal 7 vocabularies source from database.
+ *
+ * @MigrateSource(
+ *   id = "d7_taxonomy_vocabulary",
+ *   source_provider = "taxonomy"
+ * )
+ */
+class Vocabulary extends DrupalSqlBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    $query = $this->select('taxonomy_vocabulary', 'v')
+      ->fields('v', array(
+        'vid',
+        'name',
+        'description',
+        'hierarchy',
+        'module',
+        'weight',
+        'machine_name'
+      ));
+    $query->condition('vid', array(5,6), 'NOT IN');
+    return $query;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array(
+      'vid' => $this->t('The vocabulary ID.'),
+      'name' => $this->t('The name of the vocabulary.'),
+      'description' => $this->t('The description of the vocabulary.'),
+      'help' => $this->t('Help text to display for the vocabulary.'),
+      'relations' => $this->t('Whether or not related terms are enabled within the vocabulary. (0 = disabled, 1 = enabled)'),
+      'hierarchy' => $this->t('The type of hierarchy allowed within the vocabulary. (0 = disabled, 1 = single, 2 = multiple)'),
+      'weight' => $this->t('The weight of the vocabulary in relation to other vocabularies.'),
+      'parents' => $this->t("The Drupal term IDs of the term's parents."),
+      'node_types' => $this->t('The names of the node types the vocabulary may be used with.'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['vid']['type'] = 'integer';
+    return $ids;
+  }
+
+}
diff --git a/core/modules/migrate_drupal/src/Tests/d7/MigrateTaxonomyTermTest.php b/core/modules/migrate_drupal/src/Tests/d7/MigrateTaxonomyTermTest.php
new file mode 100644
index 0000000..77259e9
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Tests/d7/MigrateTaxonomyTermTest.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Tests\d7\MigrateTaxonomyTermTest.
+ */
+
+namespace Drupal\migrate_drupal\Tests\d7;
+
+use Drupal\migrate\MigrateExecutable;
+use Drupal\taxonomy\Entity\Term;
+use Drupal\taxonomy\TermInterface;
+
+/**
+ * Upgrade taxonomy terms.
+ *
+ * @group migrate_drupal 7.x
+ * @dumpFile d7/TaxonomyTermData.php
+ * @dumpFile d7/TaxonomyTermHierarchy.php
+ * @dumpFile d7/TaxonomyVocabulary.php
+ * @migration d7_taxonomy_term
+ */
+class MigrateTaxonomyTermTest extends MigrateDrupal7TestBase {
+
+  static $modules = array('taxonomy', 'text');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installEntitySchema('taxonomy_term');
+
+    $this->prepareMigrations(array(
+      'd7_taxonomy_vocabulary' => array(
+        array(array(1), array('tags')),
+        array(array(2), array('forums')),
+        array(array(3), array('test_vocabulary')),
+    )));
+    /** @var \Drupal\migrate\entity\Migration $migration */
+    $migration = entity_load('migration', 'd7_taxonomy_term');
+    $dumps = array(
+      $this->getDumpDirectory() . '/TaxonomyTermData.php',
+      $this->getDumpDirectory() . '/TaxonomyTermHierarchy.php',
+      $this->getDumpDirectory() . '/TaxonomyVocabulary.php',
+    );
+    $this->prepare($migration, $dumps);
+    $executable = new MigrateExecutable($migration, $this);
+    $executable->import();
+  }
+
+  protected function assertEntity($id, $expected_label, $expected_vid, $expected_description = '', $expected_weight = 0, $expected_parents = []) {
+    /** @var \Drupal\taxonomy\TermInterface $entity */
+    $entity = Term::load($id);
+    $this->assertTrue($entity instanceof TermInterface);
+    $this->assertIdentical($expected_label, $entity->label());
+    $this->assertIdentical($expected_vid, $entity->getVocabularyId());
+    $this->assertEqual($expected_description, $entity->getDescription());
+    $this->assertEqual($expected_weight, $entity->getWeight());
+    $this->assertIdentical($expected_parents, $this->getParentIDs($id));
+  }
+
+  /**
+   * Tests the Drupal 7 taxonomy term to Drupal 8 migration.
+   */
+  public function testTaxonomyTerms() {
+    $this->assertEntity(1, 'General discussion', 'forums', '', 2);
+    $this->assertEntity(2, 'Term1', 'test_vocabulary', 'The first term.');
+    $this->assertEntity(3, 'Term2', 'test_vocabulary', 'The second term.');
+    $this->assertEntity(4, 'Term3', 'test_vocabulary', 'The third term.', 0, [3]);
+    $this->assertEntity(5, 'Custom Forum', 'forums', 'Where the cool kids are.', 3);
+    $this->assertEntity(6, 'Games', 'forums', '', 4);
+    $this->assertEntity(7, 'Minecraft', 'forums', '', 1, [6]);
+    $this->assertEntity(8, 'Half Life 3', 'forums', '', 0, [6]);
+  }
+
+  private function getParentIDs($tid) {
+    return array_keys(\Drupal::entityManager()->getStorage('taxonomy_term')->loadParents($tid));
+  }
+
+}
diff --git a/core/modules/migrate_drupal/src/Tests/d7/MigrateTaxonomyVocabularyTest.php b/core/modules/migrate_drupal/src/Tests/d7/MigrateTaxonomyVocabularyTest.php
new file mode 100644
index 0000000..1074e55
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Tests/d7/MigrateTaxonomyVocabularyTest.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Tests\d7\MigrateTaxonomyVocabularyTest.
+ */
+
+namespace Drupal\migrate_drupal\Tests\d7;
+
+use Drupal\migrate\MigrateExecutable;
+use Drupal\taxonomy\Entity\Vocabulary;
+use Drupal\taxonomy\VocabularyInterface;
+
+/**
+ * Migrate taxonomy vocabularies to taxonomy.vocabulary.*.yml.
+ *
+ * @group migrate_drupal 7.x
+ * @dumpFile d7/TaxonomyVocabulary.php
+ * @migration d7_taxonomy_vocabulary
+ */
+class MigrateTaxonomyVocabularyTest extends MigrateDrupal7TestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('taxonomy');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $migration = entity_load('migration', 'd7_taxonomy_vocabulary');
+    $dumps = array(
+      $this->getDumpDirectory() . '/TaxonomyVocabulary.php',
+    );
+    $this->prepare($migration, $dumps);
+    $executable = new MigrateExecutable($migration, $this);
+    $executable->import();
+  }
+
+  protected function assertEntity($id, $expected_label, $expected_description, $expected_hierarchy, $expected_weight) {
+    /** @var \Drupal\taxonomy\VocabularyInterface $entity */
+    $entity = Vocabulary::load($id);
+    $this->assertTrue($entity instanceof VocabularyInterface);
+    $this->assertIdentical($expected_label, $entity->label());
+    $this->assertIdentical($expected_description, $entity->getDescription());
+    $this->assertIdentical($expected_hierarchy, $entity->getHierarchy());
+    $this->assertIdentical($expected_weight, $entity->get('weight'));
+  }
+
+  /**
+   * Tests the Drupal 7 taxonomy vocabularies to Drupal 8 migration.
+   */
+  public function testTaxonomyVocabulary() {
+    $this->assertEntity('tags', 'Tags', 'Use tags to group articles on similar topics into categories.', TAXONOMY_HIERARCHY_DISABLED, 0);
+    $this->assertEntity('forums', 'Forums', 'Forum navigation vocabulary', TAXONOMY_HIERARCHY_SINGLE, -10);
+    $this->assertEntity('test_vocabulary', 'Test Vocabulary', 'This is the vocabulary description', TAXONOMY_HIERARCHY_SINGLE, 0);
+  }
+
+}
