diff --git a/search_api_autocomplete.module b/search_api_autocomplete.module
index 600e8ed..015f8f4 100644
--- a/search_api_autocomplete.module
+++ b/search_api_autocomplete.module
@@ -9,6 +9,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\search_api\Plugin\views\query\SearchApiQuery;
+use Drupal\search_api_autocomplete\Search\SearchPluginDeriverBase;
 use Drupal\search_api_page\SearchApiPageInterface;
 use Drupal\views\ViewEntityInterface;
 
@@ -197,6 +198,7 @@ function search_api_autocomplete_view_insert(ViewEntityInterface $view) {
     \Drupal::getContainer()
       ->get('plugin.manager.search_api_autocomplete.search')
       ->clearCachedDefinitions();
+    SearchPluginDeriverBase::resetStaticDerivativeCaches('views');
   }
 }
 
@@ -211,6 +213,7 @@ function search_api_autocomplete_view_delete(ViewEntityInterface $view) {
     \Drupal::getContainer()
       ->get('plugin.manager.search_api_autocomplete.search')
       ->clearCachedDefinitions();
+    SearchPluginDeriverBase::resetStaticDerivativeCaches('views');
   }
 }
 
@@ -224,6 +227,7 @@ function search_api_autocomplete_search_api_page_insert(SearchApiPageInterface $
   \Drupal::getContainer()
     ->get('plugin.manager.search_api_autocomplete.search')
     ->clearCachedDefinitions();
+  SearchPluginDeriverBase::resetStaticDerivativeCaches('page');
 }
 
 /**
@@ -236,4 +240,5 @@ function search_api_autocomplete_search_api_page_delete(SearchApiPageInterface $
   \Drupal::getContainer()
     ->get('plugin.manager.search_api_autocomplete.search')
     ->clearCachedDefinitions();
+  SearchPluginDeriverBase::resetStaticDerivativeCaches('page');
 }
diff --git a/src/Controller/AutocompleteController.php b/src/Controller/AutocompleteController.php
index 491be31..c42dbdb 100644
--- a/src/Controller/AutocompleteController.php
+++ b/src/Controller/AutocompleteController.php
@@ -82,18 +82,12 @@ public function autocomplete(SearchInterface $search_api_autocomplete_search, Re
     $matches = [];
     $search = $search_api_autocomplete_search;
 
-    if (!$search->status()|| !$search->hasValidIndex()) {
+    if (!$search->status() || !$search->hasValidIndex()) {
       return new JsonResponse($matches);
     }
 
     try {
       $keys = $request->query->get('q');
-      // If the "Transliteration" processor is enabled for the search index, we
-      // also need to transliterate the user input for autocompletion.
-      if ($search->getIndex()->isValidProcessor('transliteration')) {
-        $langcode = $this->languageManager()->getCurrentLanguage()->getId();
-        $keys = $this->transliterator->transliterate($keys, $langcode);
-      }
       $split_keys = $this->autocompleteHelper->splitKeys($keys);
       list($complete, $incomplete) = $split_keys;
       $data = $request->query->all();
@@ -106,7 +100,6 @@ public function autocomplete(SearchInterface $search_api_autocomplete_search, Re
       // Prepare the query.
       $query->setSearchId('search_api_autocomplete:' . $search->id());
       $query->addTag('search_api_autocomplete');
-      $query->preExecute();
 
       // Get total limit and per-suggester limits.
       $limit = $search->getOption('limit');
diff --git a/src/Plugin/search_api_autocomplete/suggester/Server.php b/src/Plugin/search_api_autocomplete/suggester/Server.php
index 6f58e9c..ddce5c2 100644
--- a/src/Plugin/search_api_autocomplete/suggester/Server.php
+++ b/src/Plugin/search_api_autocomplete/suggester/Server.php
@@ -2,14 +2,18 @@
 
 namespace Drupal\search_api_autocomplete\Plugin\search_api_autocomplete\suggester;
 
+use Drupal\Component\Transliteration\TransliterationInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\search_api\IndexInterface;
 use Drupal\search_api\Plugin\PluginFormTrait;
 use Drupal\search_api\Query\QueryInterface;
+use Drupal\search_api\SearchApiException;
 use Drupal\search_api_autocomplete\AutocompleteBackendInterface;
 use Drupal\search_api_autocomplete\SearchInterface;
 use Drupal\search_api_autocomplete\Suggester\SuggesterPluginBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides a suggester plugin that retrieves suggestions from the server.
@@ -27,6 +31,20 @@ class Server extends SuggesterPluginBase implements PluginFormInterface {
 
   use PluginFormTrait;
 
+  /**
+   * The language manager.
+   *
+   * @var \Drupal\Core\Language\LanguageManagerInterface|null
+   */
+  protected $languageManager;
+
+  /**
+   * The transliteration.
+   *
+   * @var \Drupal\Component\Transliteration\TransliterationInterface|null
+   */
+  protected $transliterator;
+
   /**
    * {@inheritdoc}
    */
@@ -34,6 +52,65 @@ public static function supportsSearch(SearchInterface $search) {
     return (bool) static::getBackend($search->getIndex());
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    /** @var static $plugin */
+    $plugin = parent::create($container, $configuration, $plugin_id, $plugin_definition);
+
+    $plugin->setLanguageManager($container->get('language_manager'));
+    $plugin->setTransliterator($container->get('transliteration'));
+
+    return $plugin;
+  }
+
+  /**
+   * Retrieves the language manager.
+   *
+   * @return \Drupal\Core\Language\LanguageManagerInterface
+   *   The language manager.
+   */
+  public function getLanguageManager() {
+    return $this->languageManager ?: \Drupal::service('language_manager');
+  }
+
+  /**
+   * Sets the language manager.
+   *
+   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
+   *   The new language manager.
+   *
+   * @return $this
+   */
+  public function setLanguageManager(LanguageManagerInterface $language_manager) {
+    $this->languageManager = $language_manager;
+    return $this;
+  }
+
+  /**
+   * Retrieves the transliteration.
+   *
+   * @return \Drupal\Component\Transliteration\TransliterationInterface
+   *   The transliteration.
+   */
+  public function getTransliterator() {
+    return $this->transliterator ?: \Drupal::service('transliteration');
+  }
+
+  /**
+   * Sets the transliteration.
+   *
+   * @param \Drupal\Component\Transliteration\TransliterationInterface $transliterator
+   *   The new transliteration.
+   *
+   * @return $this
+   */
+  public function setTransliterator(TransliterationInterface $transliterator) {
+    $this->transliterator = $transliterator;
+    return $this;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -81,13 +158,28 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s
    * {@inheritdoc}
    */
   public function getAutocompleteSuggestions(QueryInterface $query, $incomplete_key, $user_input) {
-    if (!($backend = static::getBackend($this->getSearch()->getIndex()))) {
+    $index = $query->getIndex();
+    if (!($backend = static::getBackend($index))) {
       return [];
     }
 
+    // If the "Transliteration" processor is enabled for the search index, we
+    // also need to transliterate the user input for autocompletion.
+    if ($index->isValidProcessor('transliteration')) {
+      $langcode = $this->getLanguageManager()->getCurrentLanguage()->getId();
+      $incomplete_key = $this->getTransliterator()->transliterate($incomplete_key, $langcode);
+      $user_input = $this->getTransliterator()->transliterate($user_input, $langcode);
+    }
+
     if ($this->configuration['fields']) {
       $query->setFulltextFields($this->configuration['fields']);
     }
+    try {
+      $query->preExecute();
+    }
+    catch (SearchApiException $e) {
+      return [];
+    }
     return $backend->getAutocompleteSuggestions($query, $this->getSearch(), $incomplete_key, $user_input);
   }
 
@@ -105,8 +197,13 @@ protected static function getBackend(IndexInterface $index) {
     if (!$index->hasValidServer()) {
       return NULL;
     }
-    $server = $index->getServerInstance();
-    $backend = $server->getBackend();
+    try {
+      $server = $index->getServerInstance();
+      $backend = $server->getBackend();
+    }
+    catch (SearchApiException $e) {
+      return NULL;
+    }
     if ($server->supportsFeature('search_api_autocomplete') || $backend instanceof AutocompleteBackendInterface) {
       return $backend;
     }
diff --git a/src/Search/SearchPluginDeriverBase.php b/src/Search/SearchPluginDeriverBase.php
index 5da2ba4..d698b1d 100644
--- a/src/Search/SearchPluginDeriverBase.php
+++ b/src/Search/SearchPluginDeriverBase.php
@@ -15,6 +15,13 @@ abstract class SearchPluginDeriverBase extends DeriverBase implements ContainerD
 
   use StringTranslationTrait;
 
+  /**
+   * Existing instances of this class.
+   *
+   * @var \Drupal\search_api_autocomplete\Search\SearchPluginDeriverBase[][]
+   */
+  protected static $instances = [];
+
   /**
    * {@inheritdoc}
    */
@@ -36,9 +43,28 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
     $deriver->setEntityTypeManager($container->get('entity_type.manager'));
     $deriver->setStringTranslation($container->get('string_translation'));
 
+    static::$instances[$base_plugin_id][] = $deriver;
+
     return $deriver;
   }
 
+  /**
+   * Resets the statically cached derivatives for all instances of this class.
+   *
+   * @param string|null $base_plugin_id
+   *   (optional) If given, only reset the caches on derivers for the given base
+   *   plugin ID.
+   */
+  public static function resetStaticDerivativeCaches($base_plugin_id = NULL) {
+    $instances = static::$instances;
+    if ($base_plugin_id) {
+      $instances = !empty($instances[$base_plugin_id]) ? $instances[$base_plugin_id] : [];
+    }
+    foreach ($instances as $deriver) {
+      $deriver->derivatives = NULL;
+    }
+  }
+
   /**
    * Retrieves the entity manager.
    *
diff --git a/tests/src/FunctionalJavascript/IntegrationTest.php b/tests/src/FunctionalJavascript/IntegrationTest.php
index b3e4384..492df95 100644
--- a/tests/src/FunctionalJavascript/IntegrationTest.php
+++ b/tests/src/FunctionalJavascript/IntegrationTest.php
@@ -232,23 +232,23 @@ protected function checkSearchAutocomplete($click_url_suggestion = FALSE) {
     }
     $expected = [
       [
-        'keys' => 'test-suggester-1',
+        'keys' => 'Tést-suggester-1',
         'count' => 1,
       ],
       [
-        'keys' => 'test-suggester-2',
+        'keys' => 'Tést-suggester-2',
         'count' => 2,
       ],
       [
-        'keys' => 'test-suggester-url',
+        'keys' => 'Tést-suggester-url',
         'count' => NULL,
       ],
       [
-        'keys' => 'test-backend-1',
+        'keys' => 'Tést-backend-1',
         'count' => 1,
       ],
       [
-        'keys' => 'test-backend-2',
+        'keys' => 'Tést-backend-2',
         'count' => 2,
       ],
     ];
@@ -264,17 +264,19 @@ protected function checkSearchAutocomplete($click_url_suggestion = FALSE) {
     if ($click_url_suggestion) {
       // Click the URL suggestion and verify it correctly redirects the browser
       // to that URL.
-      $suggestion_elements['test-suggester-url']->click();
+      $suggestion_elements['Tést-suggester-url']->click();
       $this->logPageChange();
       $assert_session->addressEquals("/user/{$this->adminUser->id()}");
       return;
     }
 
     // Click one of the search key suggestions. The form should now auto-submit.
-    $suggestion_elements['test-suggester-1']->click();
+    $keys = 'Tést-suggester-1';
+    $suggestion_elements[$keys]->click();
     $this->logPageChange();
     $assert_session->addressEquals('/search-api-autocomplete-test');
-    $this->assertRegExp('#[?&]keys=test-suggester-1#', $this->getUrl());
+    $keys = urlencode($keys);
+    $this->assertRegExp("#[?&]keys=$keys#", $this->getUrl());
 
     // Check that autocomplete in the "Name" filter works, too, and that it sets
     // the correct fields on the query.
@@ -328,7 +330,7 @@ protected function checkLiveResultsAutocomplete() {
     $this->assertEquals(0, $query->getOption('offset'));
     $this->assertEquals(5, $query->getOption('limit'));
     $this->assertEquals(['body'], $query->getFulltextFields());
-    $this->assertEquals('test', $query->getOriginalKeys());
+    $this->assertEquals('Tést', $query->getOriginalKeys());
 
     // Click on one of the suggestions and verify it takes us to the expected
     // page.
@@ -338,33 +340,6 @@ protected function checkLiveResultsAutocomplete() {
     $assert_session->addressEquals('/' . $path);
   }
 
-  /**
-   * Retrieves autocomplete suggestions from a field on the current page.
-   *
-   * @param string $field_html_id
-   *   (optional) The HTML ID of the field.
-   * @param string $input
-   *   (optional) The input to write into the field.
-   *
-   * @return \Behat\Mink\Element\NodeElement[]
-   *   The suggestion elements from the page.
-   */
-  protected function getAutocompleteSuggestions($field_html_id = 'edit-keys', $input = 'test') {
-    $assert_session = $this->assertSession();
-    $field = $assert_session->elementExists('css', "input[data-drupal-selector=\"$field_html_id\"]");
-    $field->setValue(substr($input, 0, -1));
-    $this->getSession()->getDriver()->keyDown($field->getXpath(), substr($input, -1));
-
-    $element = $assert_session->waitOnAutocomplete();
-    $this->assertTrue($element && $element->isVisible());
-    $this->logPageChange();
-
-    // Contrary to documentation, this can also return NULL. Therefore, we need
-    // to make sure to return an array even in this case.
-    $page = $this->getSession()->getPage();
-    return $page->findAll('css', '.ui-autocomplete .ui-menu-item') ?: [];
-  }
-
   /**
    * Tests whether using a custom autocomplete script is properly supported.
    *
@@ -403,7 +378,7 @@ protected function checkCustomAutocompleteScript() {
     $expected = [
       'display: page',
       'filter: keys',
-      'q: test',
+      'q: Tést',
       "search_api_autocomplete_search: {$this->searchId}",
     ];
     $this->assertEquals($expected, $suggestions, 'Unexpected suggestions returned by custom script.');
diff --git a/tests/src/FunctionalJavascript/IntegrationTestBase.php b/tests/src/FunctionalJavascript/IntegrationTestBase.php
index 232a26e..b7a93dc 100644
--- a/tests/src/FunctionalJavascript/IntegrationTestBase.php
+++ b/tests/src/FunctionalJavascript/IntegrationTestBase.php
@@ -27,12 +27,14 @@ abstract class IntegrationTestBase extends JavascriptTestBase {
    * @param string $field_html_id
    *   (optional) The HTML ID of the field.
    * @param string $input
-   *   (optional) The input to write into the field.
+   *   (optional) The input to write into the field. The default contains
+   *   uppercase characters and accents to verify input is properly
+   *   preprocessed.
    *
    * @return \Behat\Mink\Element\NodeElement[]
    *   The suggestion elements from the page.
    */
-  protected function getAutocompleteSuggestions($field_html_id = 'edit-keys', $input = 'test') {
+  protected function getAutocompleteSuggestions($field_html_id = 'edit-keys', $input = 'Tést') {
     $page = $this->getSession()->getPage();
     $assert_session = $this->assertSession();
     $field = $assert_session->elementExists('css', "input[data-drupal-selector=\"$field_html_id\"]");
diff --git a/tests/src/FunctionalJavascript/PagesIntegrationTest.php b/tests/src/FunctionalJavascript/PagesIntegrationTest.php
index b1a3f36..88d540d 100644
--- a/tests/src/FunctionalJavascript/PagesIntegrationTest.php
+++ b/tests/src/FunctionalJavascript/PagesIntegrationTest.php
@@ -167,7 +167,6 @@ protected function checkAutocompleteFunctionality() {
 
     $elements = $this->getAutocompleteSuggestions();
     $suggestions = [];
-    $suggestion_elements = [];
     foreach ($elements as $element) {
       $label = $this->getElementText($element, '.autocomplete-suggestion-label');
       $user_input = $this->getElementText($element, '.autocomplete-suggestion-user-input');
@@ -178,27 +177,26 @@ protected function checkAutocompleteFunctionality() {
         'keys' => $keys,
         'count' => $count,
       ];
-      $suggestion_elements[$keys] = $element;
     }
     $expected = [
       [
-        'keys' => 'test-suggester-1',
+        'keys' => 'Tést-suggester-1',
         'count' => 1,
       ],
       [
-        'keys' => 'test-suggester-2',
+        'keys' => 'Tést-suggester-2',
         'count' => 2,
       ],
       [
-        'keys' => 'test-suggester-url',
+        'keys' => 'Tést-suggester-url',
         'count' => NULL,
       ],
       [
-        'keys' => 'test-backend-1',
+        'keys' => 'Tést-backend-1',
         'count' => 1,
       ],
       [
-        'keys' => 'test-backend-2',
+        'keys' => 'Tést-backend-2',
         'count' => 2,
       ],
     ];
diff --git a/tests/src/Kernel/ViewsTest.php b/tests/src/Kernel/ViewsTest.php
index 1a39d20..c352b24 100644
--- a/tests/src/Kernel/ViewsTest.php
+++ b/tests/src/Kernel/ViewsTest.php
@@ -212,4 +212,60 @@ public function formAlteringDataProvider() {
     ];
   }
 
+  /**
+   * Tests that the deriver works correctly.
+   *
+   * @see \Drupal\search_api_autocomplete\Plugin\search_api_autocomplete\search\ViewsDeriver
+   */
+  public function testDeriver() {
+    $searches = $this->container
+      ->get('plugin.manager.search_api_autocomplete.search')
+      ->getDefinitions();
+    $expected = ['search_api_autocomplete_test'];
+    $this->assertEquals($expected, array_keys($searches));
+
+    $this->installConfig('search_api_autocomplete_test');
+
+    $searches = $this->container
+      ->get('plugin.manager.search_api_autocomplete.search')
+      ->getDefinitions();
+    ksort($searches);
+    $expected = [
+      'search_api_autocomplete_test',
+      'views:search_api_autocomplete_test_view',
+    ];
+    $this->assertEquals($expected, array_keys($searches));
+
+    View::create([
+      'id' => 'second_test_view',
+      'base_field' => 'search_api_id',
+      'base_table' => 'search_api_index_autocomplete_search_index',
+      'core' => '8.x',
+      'display' => [
+        'default' => [
+          'display_plugin' => 'default',
+          'id' => 'default',
+          'display_title' => 'Master',
+          'position' => 0,
+          'display_options' => [
+            'query' => [
+              'type' => 'search_api_query',
+            ],
+          ],
+        ],
+      ],
+    ])->save();
+
+    $searches = $this->container
+      ->get('plugin.manager.search_api_autocomplete.search')
+      ->getDefinitions();
+    ksort($searches);
+    $expected = [
+      'search_api_autocomplete_test',
+      'views:search_api_autocomplete_test_view',
+      'views:second_test_view',
+    ];
+    $this->assertEquals($expected, array_keys($searches));
+  }
+
 }
