diff --git a/dynamic_entity_reference.routing.yml b/dynamic_entity_reference.routing.yml
deleted file mode 100644
index 96304e5..0000000
--- a/dynamic_entity_reference.routing.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-dynamic_entity_reference.autocomplete:
-  path: '/dynamic_entity_reference/autocomplete/{field_name}/{entity_type}/{bundle_name}/{target_type}/{entity_id}'
-  defaults:
-    _controller: '\Drupal\dynamic_entity_reference\DynamicEntityReferenceController::handleAutocomplete'
-    entity_id: 'NULL'
-  requirements:
-    _access: 'TRUE'
diff --git a/js/dynamic-entity-reference-widget.js b/js/dynamic-entity-reference-widget.js
index b3e246b..3a36dd7 100644
--- a/js/dynamic-entity-reference-widget.js
+++ b/js/dynamic-entity-reference-widget.js
@@ -8,45 +8,22 @@
   "use strict";
 
   Drupal.behaviors.dynamicEntityReferenceWidget = {
-    attach: function (context) {
-      var $context = $(context);
-      var $selects = $context.find('select.dynamic-entity-reference-entity-type').once('dynamic-entity-reference');
-      if ($selects.length) {
-        $selects.change(function() {
-          var $select = $(this);
-          var $autocomplete = $select.parents('.container-inline').find('.form-autocomplete');
-          var basePath;
-          var entityId = $autocomplete.data('entity-id');
-          if (!(basePath = $autocomplete.data('base-autocomplete-path'))) {
-            // This is the first time this has run, copy the default value.
-            var autocompletePath = $autocomplete.attr('data-autocomplete-path');
-            entityId = autocompletePath.substring(autocompletePath.lastIndexOf('/') + 1, autocompletePath.length);
-            if ($.isNumeric(entityId)) {
-              // By default, the base path contains the default suffix, so cut
-              // that off.
-              basePath = autocompletePath.substring(0, autocompletePath.lastIndexOf('/'));
-              basePath = basePath.substring(0, basePath.lastIndexOf('/') + 1);
-
-            }
-            else {
-              entityId = null;
-              // By default, the base path contains the default suffix, so cut
-              // that off.
-              basePath = autocompletePath.substring(0, autocompletePath.lastIndexOf('/') + 1);
-            }
-            // Store for subsequent calls.
-            $autocomplete.data('base-autocomplete-path', basePath);
-            $autocomplete.data('entity-id', entityId);
-          }
-          if (entityId) {
-            $autocomplete.attr('data-autocomplete-path', basePath + $select.val() + '/' + entityId);
-          }
-          else {
-            $autocomplete.attr('data-autocomplete-path', basePath + $select.val());
-          }
-        });
-        $selects.change();
+    attach: function (context, settings) {
+      function dynamicEntityReferenceWidgetSelect(e) {
+        var data = e.data;
+        var $select = $(data.select);
+        var $autocomplete = $select.parents('.container-inline').find('.form-autocomplete');
+        var entityTypeId = $select.val();
+        $autocomplete.attr('data-autocomplete-path', settings.dynamic_entity_reference[$select[0].name][entityTypeId]);
       }
+      var $context = $(context);
+      Object.keys(settings.dynamic_entity_reference).forEach(function(fieldName){
+        var select = 'select[name="' + fieldName + '"]';
+        $(select)
+          .once('dynamic-entity-reference')
+          .on('change', {select: select}, dynamicEntityReferenceWidgetSelect)
+          .trigger('change');
+      });
     }
   };
 
diff --git a/src/DynamicEntityReferenceController.php b/src/DynamicEntityReferenceController.php
deleted file mode 100644
index ce1e4f6..0000000
--- a/src/DynamicEntityReferenceController.php
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\dynamic_entity_reference/DynamicEntityReferenceController.
- */
-
-namespace Drupal\dynamic_entity_reference;
-
-use Drupal\Component\Utility\Tags;
-use Drupal\Component\Utility\Unicode;
-use Drupal\Core\Controller\ControllerBase;
-use Drupal\Core\Entity\EntityAutocompleteMatcher;
-use Drupal\dynamic_entity_reference\Plugin\Field\FieldType\DynamicEntityReferenceItem;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\JsonResponse;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
-
-/**
- * Defines route controller for dynamic entity reference.
- */
-class DynamicEntityReferenceController extends ControllerBase {
-
-  /**
-   * The entity query object.
-   *
-   * @var \Drupal\Core\Entity\EntityAutocompleteMatcher
-   */
-  protected $matcher;
-
-  /**
-   * Constructs a DynamicEntityReferenceController object.
-   *
-   * @param \Drupal\Core\Entity\EntityAutocompleteMatcher $matcher
-   *   The autocomplete matcher for entity references.
-   */
-  public function __construct(EntityAutocompleteMatcher $matcher) {
-    $this->matcher = $matcher;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('entity.autocomplete_matcher')
-    );
-  }
-
-  /**
-   * Autocomplete the label of an entity.
-   *
-   * @param Request $request
-   *   The request object that contains the typed tags.
-   * @param string $field_name
-   *   The name of the entity reference field.
-   * @param string $entity_type
-   *   The entity type.
-   * @param string $bundle_name
-   *   The bundle name.
-   * @param string $target_type
-   *   The target entity type ID to search for results.
-   * @param string $entity_id
-   *   (optional) The entity ID the entity reference field is attached to.
-   *   Defaults to ''.
-   *
-   * @return \Symfony\Component\HttpFoundation\JsonResponse
-   *   The matched labels as json.
-   */
-  public function handleAutocomplete(Request $request, $field_name, $entity_type, $bundle_name, $target_type, $entity_id) {
-    $matches = array();
-    $definitions = $this->entityManager()->getFieldDefinitions($entity_type, $bundle_name);
-
-    if (!isset($definitions[$field_name])) {
-      throw new AccessDeniedHttpException();
-    }
-    /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
-    $field_definition = $definitions[$field_name];
-    $access_control_handler = $this->entityManager()->getAccessControlHandler($entity_type);
-    if ($field_definition->getType() != 'dynamic_entity_reference' || !$access_control_handler->fieldAccess('edit', $field_definition)) {
-      throw new AccessDeniedHttpException();
-    }
-
-    $settings = $field_definition->getSettings();
-    $target_types = DynamicEntityReferenceItem::getTargetTypes($settings);
-    if (!in_array($target_type, array_keys($target_types))) {
-      throw new AccessDeniedHttpException();
-    }
-    $selection_handler = $settings[$target_type]['handler'];
-    $selection_settings = $settings[$target_type]['handler_settings'];
-
-    // Get the typed string from the URL, if it exists.
-    if ($input = $request->query->get('q')) {
-      $typed_string = Tags::explode($input);
-      $typed_string = Unicode::strtolower(array_pop($typed_string));
-
-      // Selection settings are passed in as an encoded serialized array.
-      $selection_settings = $selection_settings ? unserialize(base64_decode($selection_settings)) : array();
-
-      $matches = $this->matcher->getMatches($target_type, $selection_handler, $selection_settings, $typed_string);
-    }
-
-    return new JsonResponse($matches);
-  }
-
-}
diff --git a/src/Plugin/Field/FieldWidget/DynamicEntityReferenceWidget.php b/src/Plugin/Field/FieldWidget/DynamicEntityReferenceWidget.php
index 159c247..1ebe9ea 100644
--- a/src/Plugin/Field/FieldWidget/DynamicEntityReferenceWidget.php
+++ b/src/Plugin/Field/FieldWidget/DynamicEntityReferenceWidget.php
@@ -7,9 +7,11 @@
 
 namespace Drupal\dynamic_entity_reference\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Entity\EntityFormInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
 use Drupal\dynamic_entity_reference\Plugin\Field\FieldType\DynamicEntityReferenceItem;
 use Drupal\user\EntityOwnerInterface;
 
@@ -32,43 +34,46 @@ class DynamicEntityReferenceWidget extends EntityReferenceAutocompleteWidget {
    */
   public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
     $entity = $items->getEntity();
-    $target = $items->get($delta)->entity;
+    $referenced_entities = $items->referencedEntities();
 
-    $available = DynamicEntityReferenceItem::getTargetTypes($this->getFieldSettings());
+    $settings = $this->getFieldSettings();
+    $available = DynamicEntityReferenceItem::getTargetTypes($settings);
     $cardinality = $items->getFieldDefinition()->getFieldStorageDefinition()->getCardinality();
-
-    // Prepare the autocomplete route parameters.
-    $autocomplete_route_parameters = array(
-      'field_name' => $this->fieldDefinition->getName(),
-      'entity_type' => $entity->getEntityTypeId(),
-      'bundle_name' => $entity->bundle(),
-      'target_type' => $items->get($delta)->target_type ?: key($available),
-    );
-
-    if ($entity_id = $entity->id()) {
-      $autocomplete_route_parameters['entity_id'] = $entity_id;
-    }
+    $target_type = $items->get($delta)->target_type ?: key($available);
 
     $element += array(
-      '#type' => 'textfield',
+      '#type' => 'entity_autocomplete',
+      '#target_type' => $target_type,
+      '#selection_handler' => $settings[$target_type]['handler'],
+      '#selection_settings' => $settings[$target_type]['handler_settings'],
+      // Dynamic entity reference field items are handling validation themselves
+      // via the 'ValidDynamicReference' constraint.
+      '#validate_reference' => FALSE,
       '#maxlength' => 1024,
-      '#default_value' => $target ? $target->label() . ' (' . $target->id() . ')' : '',
-      '#autocomplete_route_name' => 'dynamic_entity_reference.autocomplete',
-      '#autocomplete_route_parameters' => $autocomplete_route_parameters,
+      '#default_value' => isset($referenced_entities[$delta]) ? $referenced_entities[$delta] : NULL,
       '#size' => $this->getSetting('size'),
       '#placeholder' => $this->getSetting('placeholder'),
-      '#element_validate' => array(array($this, 'elementValidate')),
-      '#autocreate_uid' => ($entity instanceof EntityOwnerInterface) ? $entity->getOwnerId() : \Drupal::currentUser()->id(),
+      '#element_validate' => array_merge(
+        array(array($this, 'elementValidate')),
+        element_info_property('entity_autocomplete', '#element_validate', array())
+      ),
       '#field_name' => $items->getName(),
     );
 
+    if ($this->getSelectionHandlerSetting('auto_create', $target_type)) {
+      $element['#autocreate'] = array(
+        'bundle' => $this->getAutocreateBundle($target_type),
+        'uid' => ($entity instanceof EntityOwnerInterface) ? $entity->getOwnerId() : \Drupal::currentUser()->id(),
+      );
+    }
+
     $element['#title'] = $this->t('Label');
 
     $entity_type = array(
       '#type' => 'select',
       '#options' => $available,
       '#title' => $this->t('Entity type'),
-      '#default_value' => $items->get($delta)->target_type,
+      '#default_value' => $target_type,
       '#weight' => -50,
       '#attributes' => array(
         'class' => array('dynamic-entity-reference-entity-type'),
@@ -86,6 +91,11 @@ class DynamicEntityReferenceWidget extends EntityReferenceAutocompleteWidget {
         'library' => array(
           'dynamic_entity_reference/drupal.dynamic_entity_reference_widget',
         ),
+        'drupalSettings' => array(
+          'dynamic_entity_reference' => array(
+            "{$items->getName()}[$delta][target_type]" => $this->createAutoCompletePaths(array_keys($available)),
+          ),
+        ),
       ),
     );
     // Render field as details.
@@ -98,28 +108,9 @@ class DynamicEntityReferenceWidget extends EntityReferenceAutocompleteWidget {
   }
 
   /**
-   * Checks whether a content entity is referenced.
-   *
-   * @param string $target_type
-   *   The value target entity type.
-   *
-   * @return bool
-   *   TRUE if a content entity is referenced.
-   */
-  protected function isContentReferenced($target_type = NULL) {
-    if ($target_type === NULL) {
-      return parent::isContentReferenced();
-    }
-    $target_type_info = \Drupal::entityManager()->getDefinition($target_type);
-    return $target_type_info->isSubclassOf('\Drupal\Core\Entity\ContentEntityInterface');
-  }
-
-  /**
    * {@inheritdoc}
    */
-  public function elementValidate($element, FormStateInterface $form_state, $form) {
-    // If a value was entered into the autocomplete.
-    $value = NULL;
+  public function elementValidate(&$element, FormStateInterface $form_state, &$form) {
     if (!empty($element['#value'])) {
       // If this is the default value of the field.
       if ($form_state->hasValue('default_value_input')) {
@@ -135,37 +126,23 @@ class DynamicEntityReferenceWidget extends EntityReferenceAutocompleteWidget {
           $element['#delta'],
         ));
       }
-      // Take "label (entity id)', match the id from parenthesis.
-      if ($this->isContentReferenced($values['target_type']) && preg_match("/.+\((\d+)\)/", $element['#value'], $matches)) {
-        $value = $matches[1];
-      }
-      elseif (preg_match("/.+\(([\w.]+)\)/", $element['#value'], $matches)) {
-        $value = $matches[1];
-      }
-      $auto_create = $this->getSelectionHandlerSetting('auto_create', $values['target_type']);
-      // Try to get a match from the input string when the user didn't use the
-      // autocomplete but filled in a value manually.
-      if ($value === NULL) {
-        /** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface $handler */
-        $handler = \Drupal::service('plugin.manager.dynamic_entity_reference_selection')->getSelectionHandler($this->fieldDefinition, NULL, $values['target_type']);
-        $value = $handler->validateAutocompleteInput($element['#value'], $element, $form_state, $form, !$auto_create);
-      }
-      // Auto-create item. See
-      // \Drupal\Core\Field\Plugin\Field\FieldType\DynamicEntityReferenceItem::presave().
-      if (!$value && $auto_create && (count($this->getSelectionHandlerSetting('target_bundles', $values['target_type'])) == 1)) {
-        $value = array(
-          'target_id' => NULL,
-          'entity' => $this->createNewEntity($element['#value'], $element['#autocreate_uid'], $values['target_type']),
-          // Keep the weight property.
-          '_weight' => $element['#weight'],
+      $settings = $this->getFieldSettings();
+      $element['#target_type'] = $values['target_type'];
+      $element['#selection_handler'] = $settings[$values['target_type']]['handler'];
+      $element['#selection_settings'] = $settings[$values['target_type']]['handler_settings'];
+      if ($this->getSelectionHandlerSetting('auto_create', $values['target_type'])) {
+        $form_object = $form_state->getFormObject();
+        $entity =  $form_object instanceof EntityFormInterface ? $form_object->getEntity() : '';
+        $element['#autocreate'] = array(
+          'bundle' => $this->getAutocreateBundle($values['target_type']),
+          'uid' => ($entity instanceof EntityOwnerInterface) ? $entity->getOwnerId() : \Drupal::currentUser()->id()
         );
-        // Change the element['#parents'], so in form_set_value() we populate
-        // the correct key.
-        array_pop($element['#parents']);
+      }
+      else {
+        $element['#autocreate'] = NULL;
       }
 
     }
-    $form_state->setValueForElement($element, $value);
   }
 
   /**
@@ -187,49 +164,52 @@ class DynamicEntityReferenceWidget extends EntityReferenceAutocompleteWidget {
     return isset($settings[$target_type]['handler_settings'][$setting_name]) ? $settings[$target_type]['handler_settings'][$setting_name] : NULL;
   }
 
-  /**
-   * Creates a new entity from a label entered in the autocomplete input.
-   *
-   * @param string $label
-   *   The entity label.
-   * @param int $uid
-   *   The entity uid.
-   * @param string $target_type
-   *   The target entity type id.
-   *
-   * @return \Drupal\Core\Entity\EntityInterface
-   *   The newly created entity.
+  /*
+   * {@inheritdoc}
    */
-  protected function createNewEntity($label, $uid, $target_type = NULL) {
+  protected function getAutocreateBundle($target_type = NULL) {
     if ($target_type === NULL) {
-      return parent::createNewEntity($label, $uid);
-    }
-    $entity_manager = \Drupal::entityManager();
-    $target_bundles = $this->getSelectionHandlerSetting('target_bundles', $target_type);
-
-    // Get the bundle.
-    if (!empty($target_bundles)) {
-      $bundle = reset($target_bundles);
+      return parent::getAutocreateBundle();
     }
-    else {
-      $bundles = $entity_manager->getBundleInfo($target_type);
-      $bundle = reset($bundles);
+    $bundle = NULL;
+    if ($this->getSelectionHandlerSetting('auto_create', $target_type)) {
+      // If the 'target_bundles' setting is restricted to a single choice, we
+      // can use that.
+      if (($target_bundles = $this->getSelectionHandlerSetting('target_bundles', $target_type)) && count($target_bundles) == 1) {
+        $bundle = reset($target_bundles);
+      }
+      // Otherwise use the first bundle as a fallback.
+      else {
+        // @todo Expose a proper UI for choosing the bundle for autocreated
+        // entities in https://www.drupal.org/node/2412569.
+        $bundles = entity_get_bundles($target_type);
+        $bundle = key($bundles);
+      }
     }
 
-    $entity_type = $entity_manager->getDefinition($target_type);
-    $bundle_key = $entity_type->getKey('bundle');
-    $label_key = $entity_type->getKey('label');
-
-    $entity = $entity_manager->getStorage($target_type)->create(array(
-      $label_key => $label,
-      $bundle_key => $bundle,
-    ));
+    return $bundle;
+  }
 
-    if ($entity instanceof EntityOwnerInterface) {
-      $entity->setOwnerId($uid);
+  /*
+   * Creates auto complete path for all the given target types
+   *
+   * @param string[] $target_types
+   *   All the referenceable target types.
+   *
+   * @return array
+   *   Auto complete paths for all the referenceable target types.
+   */
+  protected function createAutoCompletePaths($target_types) {
+    $auto_complete_paths = array();
+    $settings = $this->getFieldSettings();
+    foreach ($target_types as $target_type) {
+      $auto_complete_paths[$target_type] = Url::fromRoute('system.entity_autocomplete', array(
+        'target_type' => $target_type,
+        'selection_handler' => $settings[$target_type]['handler'],
+        'selection_settings' => $settings[$target_type]['handler_settings'] ? base64_encode(serialize($settings[$target_type]['handler_settings'])) : '',
+      ))->toString();
     }
-
-    return $entity;
+    return $auto_complete_paths;
   }
 
 }
diff --git a/src/Tests/DynamicEntityReferenceTest.php b/src/Tests/DynamicEntityReferenceTest.php
index 9b03cd5..ffc01ec 100644
--- a/src/Tests/DynamicEntityReferenceTest.php
+++ b/src/Tests/DynamicEntityReferenceTest.php
@@ -10,6 +10,7 @@ namespace Drupal\dynamic_entity_reference\Tests;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\Url;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\field\Entity\FieldStorageConfig;
 use Drupal\simpletest\WebTestBase;
@@ -196,7 +197,12 @@ class DynamicEntityReferenceTest extends WebTestBase {
 
     // Ensure that the autocomplete path is correct.
     $input = $this->xpath('//input[@name=:name]', array(':name' => 'field_foobar[0][target_id]'))[0];
-    $expected_autocomplete_path = 'dynamic_entity_reference/autocomplete/field_foobar/entity_test/entity_test/entity_test_label';
+    $settings = FieldConfig::loadByName('entity_test', 'entity_test', 'field_foobar')->getSettings();
+    $expected_autocomplete_path = Url::fromRoute('system.entity_autocomplete', array(
+      'target_type' => 'entity_test_label',
+      'selection_handler' => $settings['entity_test_label']['handler'],
+      'selection_settings' => $settings['entity_test_label']['handler_settings'] ? base64_encode(serialize($settings['entity_test_label']['handler_settings'])) : '',
+    ))->toString();
     $this->assertTrue(strpos((string) $input['data-autocomplete-path'], $expected_autocomplete_path) !== FALSE);
 
     // Add some extra dynamic entity reference fields.
@@ -216,7 +222,9 @@ class DynamicEntityReferenceTest extends WebTestBase {
     );
 
     $this->drupalPostForm(NULL, $edit, t('Save'));
-    $entities = entity_load_multiple_by_properties('entity_test', array(
+    $entities = \Drupal::entityManager()
+      ->getStorage('entity_test')
+      ->loadByProperties(array(
       'name' => 'Barfoo',
     ));
     $this->assertEqual(1, count($entities), 'Entity was saved');
@@ -237,7 +245,11 @@ class DynamicEntityReferenceTest extends WebTestBase {
     // Ensure that the autocomplete path is correct.
     foreach (array('0' => 'user', '1' => 'entity_test', '2' => 'entity_test') as $index => $expected_entity_type) {
       $input = $this->xpath('//input[@name=:name]', array(':name' => 'field_foobar[' . $index . '][target_id]'))[0];
-      $expected_autocomplete_path = 'dynamic_entity_reference/autocomplete/field_foobar/entity_test/entity_test/' . $expected_entity_type;
+      $expected_autocomplete_path = Url::fromRoute('system.entity_autocomplete', array(
+        'target_type' => $expected_entity_type,
+        'selection_handler' => $settings[$expected_entity_type]['handler'],
+        'selection_settings' => $settings[$expected_entity_type]['handler_settings'] ? base64_encode(serialize($settings[$expected_entity_type]['handler_settings'])) : '',
+      ))->toString();
       $this->assertTrue(strpos((string) $input['data-autocomplete-path'], $expected_autocomplete_path) !== FALSE);
     }
 
@@ -378,7 +390,9 @@ class DynamicEntityReferenceTest extends WebTestBase {
     );
 
     $this->drupalPostForm(NULL, $edit, t('Save'));
-    $entities = entity_load_multiple_by_properties('entity_test', array(
+    $entities = \Drupal::entityManager()
+      ->getStorage('entity_test')
+      ->loadByProperties(array(
       'name' => 'Barfoo',
     ));
     $this->assertEqual(1, count($entities), 'Entity was saved');
