diff --git a/modules/editor_ckeditor/editor_ckeditor.module b/modules/editor_ckeditor/editor_ckeditor.module
index adbf3dd..f837179 100755
--- a/modules/editor_ckeditor/editor_ckeditor.module
+++ b/modules/editor_ckeditor/editor_ckeditor.module
@@ -55,11 +55,89 @@ function editor_ckeditor_menu() {
     'type' => MENU_CALLBACK,
     'file' => 'includes/editor_ckeditor.pages.inc',
   );
+  $items['editor-ckeditor/autocomplete-entity/%/%'] = array(
+    'title' => 'Autocomplete for embedded entities',
+    'page callback' => 'editor_ckeditor_autocomplete_entity',
+    'page arguments' => array(2, 3),
+    'access callback' => 'entity_access',
+    'access arguments' => array('view', 2),
+    'type' => MENU_CALLBACK
+  );
 
   return $items;
 }
 
 /**
+ * Loads a text format object from the database.
+ *
+ * @param $format_id
+ *   The format ID.
+ *
+ * @return
+ *   A fully-populated text format object, if the requested format exists and
+ *   is enabled. If the format does not exist, or exists in the database but
+ *   has been marked as disabled, FALSE is returned.
+ *
+ * @see filter_format_exists()
+ */
+function editor_ckeditor_filter_format_load($format_id) {
+  $formats = filter_formats();
+
+  return isset($formats[$format_id]) ? $formats[$format_id] : FALSE;
+}
+
+/**
+ * Page callback: Autocomplete for entities.
+ *
+ * @param $entity_type
+ *   The type of entity to search for.
+ * @param $entity_type_bundles
+ *   The entity type bundles to restrict results to.
+ * @param $string
+ *   The search string.
+ *
+ * @return
+ *   Any matching entities output as JSON.
+ */
+function editor_ckeditor_autocomplete_entity($entity_type, $entity_type_bundles = NULL, $string) {
+  $matches = array();
+
+  $entity_type_info = entity_get_info($entity_type);
+
+  // Prevent errors if the entity type has no label key.
+  if (empty($entity_type_info['entity keys']['label'])) {
+    return drupal_json_output($matches);
+  }
+
+  $query = new EntityFieldQuery();
+  $query->entityCondition('entity_type', $entity_type)
+    ->propertyCondition($entity_type_info['entity keys']['label'], $string, 'STARTS_WITH')
+    ->range(0, 10)
+    ->propertyOrderBy($entity_type_info['entity keys']['label'], 'DESC')
+    ->execute();
+
+  // Add optional bundle restrictions.
+  if (!empty($entity_type_bundles)) {
+    $query->entityCondition('bundle', array_keys($entity_type_bundles));
+  }
+
+  $results = $query->execute();
+
+  if (!empty($results)) {
+    $ids = array_keys($results[$entity_type]);
+    $entities = entity_load($entity_type, $ids);
+
+    foreach ($entities as $entity) {
+      $label = entity_label($entity_type, $entity);
+
+      $matches[$label] = check_plain($label);
+    }
+  }
+
+  return drupal_json_output($matches);
+}
+
+/**
  * Implements hook_theme().
  */
 function editor_ckeditor_theme() {
diff --git a/modules/editor_ckeditor/includes/editor_ckeditor.pages.inc b/modules/editor_ckeditor/includes/editor_ckeditor.pages.inc
index 2c9b42d..a5a75e4 100644
--- a/modules/editor_ckeditor/includes/editor_ckeditor.pages.inc
+++ b/modules/editor_ckeditor/includes/editor_ckeditor.pages.inc
@@ -11,13 +11,27 @@
 function editor_ckeditor_link_dialog_form($form, &$form_state, $format) {
   editor_format_ensure_additional_properties($format);
 
+  $values = isset($form_state['values']) ? $form_state['values'] : array();
+  $input = $_POST;
+
+  $link_element = empty($values['attributes']) ? array() : $values['attributes'];
+
   // The default values are set directly from \Drupal::request()->request,
   // provided by the editor plugin opening the dialog.
-  $user_input = $form_state['input'];
-  $input = isset($user_input['editor_object']) ? $user_input['editor_object'] : array();
+  if (empty($form_state['link_element'])) {
+    $form_state['link_element'] = isset($input['editor_object']) ? $input['editor_object'] : array();
+  }
+
+  $link_element += $form_state['link_element'];
+  $link_element += array(
+    'data-entity-type' => '',
+    'data-entity-id' => '',
+    'data-entity-label' => '',
+    'href' => '',
+  );
 
   // Set the dialog title.
-  if (!empty($values['href'])) {
+  if (!empty($link_element['href'])) {
     drupal_set_title(t('Edit link'));
   }
   else {
@@ -28,13 +42,67 @@ function editor_ckeditor_link_dialog_form($form, &$form_state, $format) {
   $form['#prefix'] = '<div id="editor-ckeditor-link-dialog-form">';
   $form['#suffix'] = '</div>';
 
+  global $user;
+
+  $options = array();
+  $entity_types = entity_get_info();
+
+  foreach ($entity_types as $entity_type => $info) {
+    if (!empty($info['uri callback']) && entity_access('view', $entity_type, NULL, $user)) {
+      $options[$entity_type] = $info['label'];
+    }
+  }
+
+  $form['attributes']['data-entity-type'] = array(
+    '#type' => 'select',
+    '#title' => t('Entity type'),
+    '#default_value' => $link_element['data-entity-type'],
+    '#access' => count($options) > 1,
+    '#options' => $options,
+    '#empty_option' => t('- Select an entity type -'),
+    '#description' => t('Optionally create links to existing entities by selecting an entity type.'),
+    '#ajax' => array(
+      'callback' => 'editor_ckeditor_link_dialog_form_href_update',
+    ),
+  );
+
+  $default = '';
+  $entity = FALSE;
+  if (!empty($link_element['data-entity-type']) && !empty($link_element['data-entity-uuid']) && module_exists('uuid')) {
+    $entity = entity_uuid_load($link_element['data-entity-type'], array($link_element['data-entity-uuid']));
+    $entity = reset($entity);
+  }
+  elseif(!empty($link_element['data-entity-type']) && !empty($link_element['data-entity-id'])) {
+    $entity = entity_load_single($link_element['data-entity-type'], $link_element['data-entity-id']);
+  }
+
+  if ($entity) {
+    $default = entity_label($link_element['data-entity-type'], $entity);
+  }
+
+  $form['attributes']['data-entity-id'] = array(
+    '#title' => t('Entity'),
+    '#type' => !empty($link_element['data-entity-type']) ? 'textfield' : 'value',
+    '#default_value' => $default,
+    '#autocomplete_path' => 'editor-ckeditor/autocomplete-entity/' . $link_element['data-entity-type'] . '/' . NULL,
+    '#prefix' => '<div id="editor-ckeditor-link-entity-id">',
+    '#suffix' => '</div>',
+  );
+
   // Everything under the "attributes" key is merged directly into the
   // generated link tag's attributes.
   $form['attributes']['href'] = array(
     '#title' => t('URL'),
-    '#type' => 'textfield',
-    '#default_value' => isset($input['href']) ? $input['href'] : '',
+    '#type' => empty($link_element['data-entity-type']) ? 'textfield' : 'value',
+    '#default_value' => isset($link_element['href']) ? $link_element['href'] : '',
     '#maxlength' => 2048,
+    '#prefix' => '<div id="editor-ckeditor-link-href">',
+    '#suffix' => '</div>',
+  );
+
+  $form['attributes']['data-entity-label'] = array(
+    '#type' => 'value',
+    '#value' => $link_element['data-entity-label'],
   );
 
   $form['actions']['#type'] = 'actions';
@@ -56,6 +124,25 @@ function editor_ckeditor_link_dialog_form($form, &$form_state, $format) {
 }
 
 /**
+ * Re-renders the href form element when the entity type selection changes.
+ *
+ * This function is called via Ajax when the selected entity type is changed on
+ * the insert/edit link form.
+ *
+ * @return
+ *   The rendered parent page select element.
+ */
+function editor_ckeditor_link_dialog_form_href_update($form, $form_state) {
+  return array(
+    '#type' => 'ajax',
+    '#commands' => array(
+      ajax_command_replace("#editor-ckeditor-link-entity-id", render($form['attributes']['data-entity-id'])),
+      ajax_command_replace("#editor-ckeditor-link-href", render($form['attributes']['href']))
+    ),
+  );
+}
+
+/**
  * Form AJAX callback. Sends the save editor AJAX command and closes the dialog.
  *
  * @see filter_format_editor_link_form()
@@ -64,6 +151,55 @@ function editor_ckeditor_link_dialog_form($form, &$form_state, $format) {
 function editor_ckeditor_link_dialog_save($form, &$form_state) {
   $commands = array();
 
+  $values = $form_state['values'];
+
+  if ($entity_type = $values['attributes']['data-entity-type']) {
+    $title = trim($values['attributes']['data-entity-id']);
+
+    $entity_info = entity_get_info($entity_type);
+
+    // Prevent errors if the entity type has no label key.
+    if (empty($entity_info['entity keys']['label'])) {
+      form_set_error('data-entity-id', t('Unable to find label for @type entity @id.', array('@type' => $entity_type, '@id' => $title)));
+    }
+
+    // The entity ID may be either the ID (integer) of the entity or the
+    // entity's title (string).
+    if (is_numeric($title)) {
+      $entities = entity_load($entity_type, array($title));
+    }
+    else {
+      $entities = entity_load($entity_type, FALSE, array($entity_info['entity keys']['label'] => array($title)));
+    }
+
+    $entity = reset($entities);
+
+    if (!empty($entity)) {
+      list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+
+      if (!entity_access('view', $entity_type, $entity)) {
+        form_set_error('data-entity-id', t('Unable to access @type entity @id.', array('@type' => $entity_type, '@id' => $title)));
+      }
+      else {
+        $label = entity_label($entity_type, $entity);
+
+        $form_state['values']['attributes']['data-entity-id'] = $id;
+        $form_state['values']['attributes']['data-entity-label'] = $label;
+
+        $uri = entity_uri($entity_type, $entity);
+        $url = $uri && !empty($uri['path']) ? url($uri['path'], $uri['options']) : FALSE;
+
+        $form_state['values']['attributes']['href'] = $url;
+      }
+    }
+    else {
+      form_set_error('data-entity-id', t('Unable to load @type entity @id.', array('@type' => $entity_type, '@id' => $title)));
+    }
+  }
+  else {
+    $form_state['values']['attributes']['data-entity-label'] = $values['attributes']['href'];
+  }
+
   if (form_get_errors()) {
     unset($form['#prefix'], $form['#suffix']);
     $status_messages = array('#theme' => 'status_messages');
diff --git a/modules/editor_ckeditor/js/plugins/drupallink/plugin.js b/modules/editor_ckeditor/js/plugins/drupallink/plugin.js
index fd049e4..bb30b23 100755
--- a/modules/editor_ckeditor/js/plugins/drupallink/plugin.js
+++ b/modules/editor_ckeditor/js/plugins/drupallink/plugin.js
@@ -83,10 +83,10 @@
               var selection = editor.getSelection();
               var range = selection.getRanges(1)[0];
 
-              // Use link URL as text with a collapsed cursor.
+              // Use the entity label as text with a collapsed cursor.
               if (range.collapsed) {
                 // Shorten mailto URLs to just the email address.
-                var text = new CKEDITOR.dom.text(returnValues.attributes.href.replace(/^mailto:/, ''), editor.document);
+                var text = new CKEDITOR.dom.text(returnValues.attributes['data-entity-label'].replace(/^mailto:/, ''), editor.document);
                 range.insertNode(text);
                 range.selectNodeContents(text);
               }
