diff --git a/core/modules/migrate/config/schema/migrate.data_types.schema.yml b/core/modules/migrate/config/schema/migrate.data_types.schema.yml
index edb628a..d887785 100644
--- a/core/modules/migrate/config/schema/migrate.data_types.schema.yml
+++ b/core/modules/migrate/config/schema/migrate.data_types.schema.yml
@@ -14,6 +14,10 @@ migrate_destination:
 migrate_source:
   type: migrate_plugin
   label: 'Source'
+  mapping:
+    constants:
+      type: ignore
+      label: 'Constants'
 
 # Base schema for migrate source plugins that extend
 # \Drupal\migrate\Plugin\migrate\source\SqlBase.
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..721dc34
--- /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_groups:
+  - 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/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/Tests/d7/MigrateTaxonomyTermTest.php b/core/modules/migrate_drupal/src/Tests/d7/MigrateTaxonomyTermTest.php
new file mode 100644
index 0000000..bc51ff2
--- /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 TaxonomyTermData.php
+ * @dumpFile TaxonomyTermHierarchy.php
+ * @dumpFile 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));
+  }
+
+}
