diff --git a/config/schema/search_api.index.schema.yml b/config/schema/search_api.index.schema.yml
index 427f03f..6348e40 100644
--- a/config/schema/search_api.index.schema.yml
+++ b/config/schema/search_api.index.schema.yml
@@ -17,7 +17,7 @@ search_api.index.*:
     read_only:
       type: boolean
       label: 'Read-only'
-    fields:
+    field_settings:
       type: sequence
       label: 'Indexed fields'
       sequence:
@@ -48,14 +48,14 @@ search_api.index.*:
           hidden:
             type: boolean
             label: 'Whether the field should appear in the UI'
-    processors:
+    processor_settings:
       type: sequence
       label: 'Processor settings'
       sequence:
         type: mapping
         label: 'A processor'
         mapping:
-          processor_id:
+          plugin_id:
             type: string
             label: 'The plugin ID of the processor'
           weights:
@@ -65,7 +65,7 @@ search_api.index.*:
               type: integer
               label: 'The processor''s weight for this stage'
           settings:
-            type: plugin.plugin_configuration.search_api_processor.[%parent.processor_id]
+            type: plugin.plugin_configuration.search_api_processor.[%parent.plugin_id]
     options:
       type: mapping
       label: 'Options'
@@ -76,23 +76,30 @@ search_api.index.*:
         index_directly:
           type: boolean
           label: 'Index items immediately'
-    datasources:
+    datasource_settings:
       type: sequence
-      label: 'Datasource plugin IDs'
+      label: 'Datasource settings'
       sequence:
-        type: string
-    datasource_configs:
+        type: mapping
+        label: 'The settings for a datasource'
+        mapping:
+          plugin_id:
+            type: string
+            label: 'The plugin ID of the datasource'
+          settings:
+            type: plugin.plugin_configuration.search_api_datasource.[%parent.plugin_id]
+    tracker_settings:
       type: sequence
-      label: 'Datasource plugin configurations'
+      label: 'Tracker settings'
       sequence:
-        type: plugin.plugin_configuration.search_api_datasource.[%key]
-        label: 'Datasource plugin configuration'
-    tracker:
-      type: string
-      label: 'Tracker plugin ID'
-    tracker_config:
-      label: 'Tracker config plugin'
-      type: plugin.plugin_configuration.search_api_tracker.[%parent.tracker]
+        type: mapping
+        label: 'The settings for a tracker'
+        mapping:
+          plugin_id:
+            type: string
+            label: 'The plugin ID of the tracker'
+          settings:
+            type: plugin.plugin_configuration.search_api_tracker.[%parent.plugin_id]
     server:
       type: string
       label: 'Server ID'
diff --git a/config/schema/search_api.tracker.schema.yml b/config/schema/search_api.tracker.schema.yml
index 297badc..1cb3518 100644
--- a/config/schema/search_api.tracker.schema.yml
+++ b/config/schema/search_api.tracker.schema.yml
@@ -1,4 +1,3 @@
-# @todo Update the key when https://www.drupal.org/node/2291073 is fixed.
 plugin.plugin_configuration.search_api_tracker.default:
   type: sequence
   label: 'Entity tracker configuration'
diff --git a/search_api.drush.inc b/search_api.drush.inc
index e403668..e2460f7 100644
--- a/search_api.drush.inc
+++ b/search_api.drush.inc
@@ -216,7 +216,7 @@ function drush_search_api_list() {
     $rows[] = array(
       $index->id(),
       $index->label(),
-      $index->getServerId() ? $index->getServer()->label() : $none,
+      $index->getServerId() ? $index->getServerInstance()->label() : $none,
       $types ? implode(', ', $types) : $none,
       $index->status() ? $enabled : $disabled,
       (int) $index->getOption('cron_limit'),
@@ -325,8 +325,8 @@ function drush_search_api_status($index_id = NULL) {
   );
 
   foreach ($indexes as $index) {
-    $indexed = $index->getTracker()->getIndexedItemsCount();
-    $total = $index->getTracker()->getTotalItemsCount();
+    $indexed = $index->getTrackerInstance()->getIndexedItemsCount();
+    $total = $index->getTrackerInstance()->getTotalItemsCount();
 
     $complete = '-';
     if ($total > 0) {
@@ -365,7 +365,7 @@ function drush_search_api_index($index_id = NULL, $limit = NULL, $batch_size = N
   }
 
   foreach ($indexes as $index) {
-    $tracker = $index->getTracker();
+    $tracker = $index->getTrackerInstance();
     $remaining = $tracker->getTotalItemsCount() - $tracker->getIndexedItemsCount();
 
     if (!$remaining) {
diff --git a/search_api.theme.inc b/search_api.theme.inc
index 7de7c73..bc42364 100644
--- a/search_api.theme.inc
+++ b/search_api.theme.inc
@@ -229,8 +229,8 @@ function theme_search_api_index($variables) {
   // Get the index.
   /** @var $index \Drupal\search_api\IndexInterface */
   $index = $variables['index'];
-  $server = $index->hasValidServer() ? $index->getServer() : NULL;
-  $tracker = $index->hasValidTracker() ? $index->getTracker() : NULL;
+  $server = $index->hasValidServer() ? $index->getServerInstance() : NULL;
+  $tracker = $index->hasValidTracker() ? $index->getTrackerInstance() : NULL;
 
   $output = '';
 
diff --git a/search_api_db/search_api_db_defaults/config/optional/search_api.index.default_index.yml b/search_api_db/search_api_db_defaults/config/optional/search_api.index.default_index.yml
index 42d3422..6745379 100644
--- a/search_api_db/search_api_db_defaults/config/optional/search_api.index.default_index.yml
+++ b/search_api_db/search_api_db_defaults/config/optional/search_api.index.default_index.yml
@@ -7,7 +7,7 @@ fields:
     label: 'Item language'
     type: string
     property_path: search_api_language
-    index_locked: true
+    indexed_locked: true
     type_locked: true
   title:
     label: Title
@@ -34,7 +34,7 @@ fields:
     type: boolean
     datasource_id: 'entity:node'
     property_path: status
-    index_locked: true
+    indexed_locked: true
     type_locked: true
   sticky:
     label: 'Sticky at top of lists'
@@ -56,13 +56,13 @@ fields:
     type: integer
     datasource_id: 'entity:node'
     property_path: uid
-    index_locked: true
+    indexed_locked: true
     type_locked: true
   search_api_node_grants:
     label: 'Node access information'
     type: string
     property_path: search_api_node_grants
-    index_locked: true
+    indexed_locked: true
     type_locked: true
     hidden: true
   type:
@@ -71,13 +71,13 @@ fields:
     property_path: type
 processors:
   content_access:
-    processor_id: content_access
+    plugin_id: content_access
     weights:
       preprocess_index: -6
       preprocess_query: -4
     settings: {  }
   highlight:
-    processor_id: highlight
+    plugin_id: highlight
     weights:
       postprocess_query: -9
     settings:
@@ -87,7 +87,7 @@ processors:
       prefix: '<strong>'
       suffix: '</strong>'
   html_filter:
-    processor_id: html_filter
+    plugin_id: html_filter
     weights:
       preprocess_index: -3
       preprocess_query: -6
@@ -103,7 +103,7 @@ processors:
         string: 2
         b: 2
   ignorecase:
-    processor_id: ignorecase
+    plugin_id: ignorecase
     weights:
       preprocess_index: -5
       preprocess_query: -8
@@ -112,17 +112,17 @@ processors:
         - rendered_item
         - title
   language:
-    processor_id: language
+    plugin_id: language
     weights:
       preprocess_index: -50
     settings: {  }
   node_status:
-    processor_id: node_status
+    plugin_id: node_status
     weights:
       preprocess_index: -10
     settings: {  }
   rendered_item:
-    processor_id: rendered_item
+    plugin_id: rendered_item
     weights:
       preprocess_index: -8
     settings:
@@ -133,7 +133,7 @@ processors:
           article: search_index
           page: search_index
   stopwords:
-    processor_id: stopwords
+    plugin_id: stopwords
     weights:
       preprocess_query: -10
       postprocess_query: -10
@@ -178,7 +178,7 @@ processors:
         - will
         - with
   tokenizer:
-    processor_id: tokenizer
+    plugin_id: tokenizer
     weights:
       preprocess_index: -2
       preprocess_query: -5
@@ -190,7 +190,7 @@ processors:
       overlap_cjk: 1
       minimum_word_size: '3'
   transliteration:
-    processor_id: transliteration
+    plugin_id: transliteration
     weights:
       preprocess_index: -4
       preprocess_query: -7
@@ -201,16 +201,18 @@ processors:
 options:
   index_directly: true
   cron_limit: 50
-datasources:
-  - 'entity:node'
-datasource_configs:
+datasource_settings:
   'entity:node':
-    default: '1'
-    bundles:
-      article: '0'
-      page: '0'
-tracker: default
-tracker_config: {  }
+    plugin_id: 'entity:node'
+    settings:
+      default: '1'
+      bundles:
+        article: '0'
+        page: '0'
+tracker_settings:
+  default:
+    plugin_id: default
+    settings: {}
 server: default_server
 status: true
 langcode: en
diff --git a/search_api_db/tests/src/Kernel/BackendTest.php b/search_api_db/tests/src/Kernel/BackendTest.php
index 5c43111..c590c14 100644
--- a/search_api_db/tests/src/Kernel/BackendTest.php
+++ b/search_api_db/tests/src/Kernel/BackendTest.php
@@ -157,8 +157,8 @@ class BackendTest extends KernelTestBase {
     $index = $this->getIndex();
     $this->assertTrue((bool) $index, 'The index was successfully created.');
 
-    $this->assertEquals(5, $index->getTracker()->getTotalItemsCount(), 'Correct item count.');
-    $this->assertEquals(0, $index->getTracker()->getIndexedItemsCount(), 'All items still need to be indexed.');
+    $this->assertEquals(5, $index->getTrackerInstance()->getTotalItemsCount(), 'Correct item count.');
+    $this->assertEquals(0, $index->getTrackerInstance()->getIndexedItemsCount(), 'All items still need to be indexed.');
   }
 
   /**
@@ -202,7 +202,7 @@ class BackendTest extends KernelTestBase {
 
     $processors = $index->getProcessorSettings();
     $processors['html_filter'] = array(
-      'processor_id' => 'html_filter',
+      'plugin_id' => 'html_filter',
       'weights' => array(),
       'settings' => array(),
     );
diff --git a/src/Entity/Index.php b/src/Entity/Index.php
index 64e556a..abe7378 100644
--- a/src/Entity/Index.php
+++ b/src/Entity/Index.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\search_api\Entity;
 
+use Drupal\Component\Plugin\Exception\PluginException;
 use Drupal\Component\Render\FormattableMarkup;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
@@ -57,13 +58,11 @@ use Drupal\views\Views;
  *     "name",
  *     "description",
  *     "read_only",
- *     "fields",
- *     "processors",
+ *     "field_settings",
+ *     "processor_settings",
  *     "options",
- *     "datasources",
- *     "datasource_configs",
- *     "tracker",
- *     "tracker_config",
+ *     "datasource_settings",
+ *     "tracker_settings",
  *     "server",
  *   },
  *   links = {
@@ -115,7 +114,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
    *
    * @var array
    */
-  protected $fields = array();
+  protected $field_settings = array();
 
   /**
    * An array of options configuring this index.
@@ -127,18 +126,11 @@ class Index extends ConfigEntityBase implements IndexInterface {
   protected $options = array();
 
   /**
-   * The IDs of the datasources selected for this index.
-   *
-   * @var string[]
-   */
-  protected $datasources = array();
-
-  /**
    * The configuration for the selected datasources.
    *
    * @var array
    */
-  protected $datasource_configs = array();
+  protected $datasource_settings = array();
 
   /**
    * The instantiated datasource plugins.
@@ -147,30 +139,23 @@ class Index extends ConfigEntityBase implements IndexInterface {
    *
    * @see getDatasources()
    */
-  protected $datasourcePlugins;
-
-  /**
-   * The tracker plugin ID.
-   *
-   * @var string
-   */
-  protected $tracker = 'default';
+  protected $datasourceInstances;
 
   /**
    * The tracker plugin configuration.
    *
    * @var array
    */
-  protected $tracker_config = array();
+  protected $tracker_settings = array();
 
   /**
    * The tracker plugin instance.
    *
    * @var \Drupal\search_api\Tracker\TrackerInterface|null
    *
-   * @see getTracker()
+   * @see getTrackerInstance()
    */
-  protected $trackerPlugin;
+  protected $trackerInstance = NULL;
 
   /**
    * The ID of the server on which data should be indexed.
@@ -184,7 +169,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
    *
    * @var \Drupal\search_api\ServerInterface
    *
-   * @see getServer()
+   * @see getServerInstance()
    */
   protected $serverInstance;
 
@@ -201,7 +186,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
    * @var array
    *   An array containing processor settings.
    */
-  protected $processors = array();
+  protected $processor_settings = array();
 
   /**
    * Cached information about the processors available for this index.
@@ -210,7 +195,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
    *
    * @see loadProcessors()
    */
-  protected $processorPlugins;
+  protected $processorInstances;
 
   /**
    * Whether reindexing has been triggered for this index in this page request.
@@ -238,13 +223,6 @@ class Index extends ConfigEntityBase implements IndexInterface {
   /**
    * {@inheritdoc}
    */
-  public function id() {
-    return $this->id;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getDescription() {
     return $this->description;
   }
@@ -282,10 +260,6 @@ class Index extends ConfigEntityBase implements IndexInterface {
    */
   public function setOption($name, $option) {
     $this->options[$name] = $option;
-    // If the fields are changed, reset the static fields cache.
-    if ($name == 'fields') {
-      $this->cache = array();
-    }
     return $this;
   }
 
@@ -301,7 +275,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
    * {@inheritdoc}
    */
   public function getDatasourceIds() {
-    return $this->datasources;
+    return array_keys($this->getDatasources());
   }
 
   /**
@@ -320,7 +294,8 @@ class Index extends ConfigEntityBase implements IndexInterface {
     if (empty($datasources[$datasource_id])) {
       $args['@datasource'] = $datasource_id;
       $args['%index'] = $this->label();
-      throw new SearchApiException(new FormattableMarkup('The datasource with ID "@datasource" could not be retrieved for index %index.', $args));
+      $args['@all_datasources'] = implode(', ', array_keys($datasources));
+      throw new SearchApiException(new FormattableMarkup('The datasource with ID "@datasource" could not be retrieved for index %index. The available datasources are: @all_datasources', $args));
     }
     return $datasources[$datasource_id];
   }
@@ -329,20 +304,20 @@ class Index extends ConfigEntityBase implements IndexInterface {
    * {@inheritdoc}
    */
   public function getDatasources($only_enabled = TRUE) {
-    if (!isset($this->datasourcePlugins)) {
-      $this->datasourcePlugins = array();
+    if (!isset($this->datasourceInstances)) {
+      $this->datasourceInstances = array();
       /** @var $datasource_plugin_manager \Drupal\search_api\Datasource\DatasourcePluginManager */
       $datasource_plugin_manager = \Drupal::service('plugin.manager.search_api.datasource');
 
       foreach ($datasource_plugin_manager->getDefinitions() as $name => $datasource_definition) {
-        if (class_exists($datasource_definition['class']) && empty($this->datasourcePlugins[$name])) {
+        if (class_exists($datasource_definition['class']) && empty($this->datasourceInstances[$name])) {
           // Create our settings for this datasource.
-          $config = isset($this->datasource_configs[$name]) ? $this->datasource_configs[$name] : array();
+          $config = isset($this->datasource_settings[$name]) ? $this->datasource_settings[$name] : array();
           $config += array('index' => $this);
 
           /** @var $datasource \Drupal\search_api\Datasource\DatasourceInterface */
           $datasource = $datasource_plugin_manager->createInstance($name, $config);
-          $this->datasourcePlugins[$name] = $datasource;
+          $this->datasourceInstances[$name] = $datasource;
         }
         elseif (!class_exists($datasource_definition['class'])) {
           \Drupal::logger('search_api')->warning('Datasource @id specifies a non-existing @class.', array('@id' => $name, '@class' => $datasource_definition['class']));
@@ -352,53 +327,84 @@ class Index extends ConfigEntityBase implements IndexInterface {
 
     // Filter datasources by status if required.
     if (!$only_enabled) {
-      return $this->datasourcePlugins;
+      return $this->datasourceInstances;
+    }
+
+    // No settings are saved for datasources, so we can go ahead and return an
+    // empty array.
+    if ($this->datasource_settings === array()) {
+      return array();
+    }
+
+    $enabled_datasources = array_flip(array_keys($this->datasource_settings));
+    $datasource_instances = $this->datasourceInstances;
+
+    foreach ($datasource_instances as $key => $datasource) {
+      if (!isset($enabled_datasources[$key])) {
+        unset($datasource_instances[$key]);
+      }
     }
-    return array_intersect_key($this->datasourcePlugins, array_flip($this->datasources));
+
+    return $datasource_instances;
   }
 
   /**
    * {@inheritdoc}
    */
   public function hasValidTracker() {
-    return (bool) \Drupal::service('plugin.manager.search_api.tracker')->getDefinition($this->getTrackerId(), FALSE);
+    return (bool) \Drupal::service('plugin.manager.search_api.tracker')
+      ->getDefinition($this->getTrackerId(), FALSE);
   }
 
   /**
    * {@inheritdoc}
    */
   public function getTrackerId() {
-    return $this->tracker;
+    return $this->getTrackerInstance()->getPluginId();
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getTracker() {
-    if (!$this->trackerPlugin) {
-      $tracker_plugin_configuration = array('index' => $this) + $this->tracker_config;
-      if (!($this->trackerPlugin = \Drupal::service('plugin.manager.search_api.tracker')->createInstance($this->getTrackerId(), $tracker_plugin_configuration))) {
-        $args['@tracker'] = $this->tracker;
+  public function getTrackerInstance() {
+    if (!$this->trackerInstance) {
+      if ($this->tracker_settings === array()) {
+        $tracker_settings = array(
+          'settings' => array(),
+          'plugin_id' =>$default_tracker = \Drupal::config('search_api.settings')
+            ->get('default_tracker'),
+        );
+      }
+      else {
+        $tracker_settings = reset($this->tracker_settings);
+      }
+      $tracker_plugin_configuration = array('index' => $this) + $tracker_settings['settings'];
+
+      try {
+        $this->trackerInstance = \Drupal::service('plugin.manager.search_api.tracker')->createInstance($tracker_settings['plugin_id'], $tracker_plugin_configuration);
+      } catch (PluginException $pe) {
+        $args['@tracker'] = $tracker_settings['plugin_id'];
         $args['%index'] = $this->label();
         throw new SearchApiException(new FormattableMarkup('The tracker with ID "@tracker" could not be retrieved for index %index.', $args));
       }
     }
 
-    return $this->trackerPlugin;
+    return $this->trackerInstance;
   }
 
   /**
    * {@inheritdoc}
    */
   public function hasValidServer() {
-    return $this->server !== NULL && Server::load($this->server) !== NULL;
+    $server = $this->getServerInstance();
+    return ($server instanceof ServerInterface);
   }
 
   /**
    * {@inheritdoc}
    */
   public function isServerEnabled() {
-    return $this->hasValidServer() && $this->getServer()->status();
+    return $this->hasValidServer() && $this->getServerInstance()->status();
   }
 
   /**
@@ -411,7 +417,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
   /**
    * {@inheritdoc}
    */
-  public function getServer() {
+  public function getServerInstance() {
     if (!$this->serverInstance && $this->server) {
       $this->serverInstance = Server::load($this->server);
       if (!$this->serverInstance) {
@@ -441,19 +447,23 @@ class Index extends ConfigEntityBase implements IndexInterface {
     // Filter processors by status if required. Enabled processors are those
     // which have settings in the "processors" option.
     if ($only_enabled) {
-      $processors_settings = $this->getProcessorSettings();
+      $processors_settings = $this->processor_settings;
       $processors = array_intersect_key($processors, $processors_settings);
     }
 
     return $processors;
   }
 
+  public function removeProcessor($plugin_id) {
+    unset($this->processor_settings[$plugin_id]);
+    $this->processorInstances = array();
+  }
+
   /**
    * {@inheritdoc}
    */
   public function getProcessorsByStage($stage, $only_enabled = TRUE) {
     $processors = $this->loadProcessors();
-    $processor_settings = $this->getProcessorSettings();
     $processor_weights = array();
 
     // Get a list of all processors meeting the criteria (stage and, optionally,
@@ -486,21 +496,25 @@ class Index extends ConfigEntityBase implements IndexInterface {
    *   The loaded processors, keyed by processor ID.
    */
   protected function loadProcessors() {
-    if (empty($this->processorPlugins)) {
+    if (empty($this->processorInstances)) {
       /** @var $processor_plugin_manager \Drupal\search_api\Processor\ProcessorPluginManager */
       $processor_plugin_manager = \Drupal::service('plugin.manager.search_api.processor');
-      $processor_settings = $this->getProcessorSettings();
+      $processor_settings = $this->processor_settings;
 
       foreach ($processor_plugin_manager->getDefinitions() as $name => $processor_definition) {
-        if (class_exists($processor_definition['class']) && empty($this->processorPlugins[$name])) {
+        if (empty($this->processorInstances[$name])) {
           // Create our settings for this processor.
           $settings = empty($processor_settings[$name]['settings']) ? array() : $processor_settings[$name]['settings'];
           $settings['index'] = $this;
 
           /** @var $processor \Drupal\search_api\Processor\ProcessorInterface */
-          $processor = $processor_plugin_manager->createInstance($name, $settings);
-          if ($processor->supportsIndex($this)) {
-            $this->processorPlugins[$name] = $processor;
+          try {
+            $processor = $processor_plugin_manager->createInstance($name, $settings);
+            if ($processor->supportsIndex($this)) {
+              $this->processorInstances[$name] = $processor;
+            }
+          } catch (PluginException $e) {
+            \Drupal::logger('search_api')->warning('Processor @id specifies a non-existing @class.', array('@id' => $name, '@class' => $processor_definition['class']));
           }
         }
         elseif (!class_exists($processor_definition['class'])) {
@@ -509,22 +523,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
       }
     }
 
-    return $this->processorPlugins;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getProcessorSettings() {
-    return $this->processors;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setProcessorSettings(array $processors) {
-    $this->processors = $processors;
-    return $this;
+    return $this->processorInstances;
   }
 
   /**
@@ -578,7 +577,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
       throw new SearchApiException(new FormattableMarkup('Cannot add field with machine name %field_id: machine name is already taken.', $args));
     }
 
-    $this->fields[$field_id] = $field->getSettings();
+    $this->field_settings[$field_id] = $field->getSettings();
 
     $this->resetCaches();
     return $this;
@@ -588,7 +587,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
    * {@inheritdoc}
    */
   public function renameField($old_field_id, $new_field_id) {
-    if (isset($this->fields[$old_field_id])) {
+    if (isset($this->field_settings[$old_field_id])) {
       $args['%field_id'] = $old_field_id;
       throw new SearchApiException(new FormattableMarkup('Could not rename field with machine name %field_id: no such field.', $args));
     }
@@ -596,13 +595,13 @@ class Index extends ConfigEntityBase implements IndexInterface {
       $args['%field_id'] = $new_field_id;
       throw new SearchApiException(new FormattableMarkup('%field_id is a reserved value and cannot be used as the machine name of a normal field.', $args));
     }
-    if (isset($this->fields[$new_field_id])) {
+    if (isset($this->field_settings[$new_field_id])) {
       $args['%field_id'] = $new_field_id;
       throw new SearchApiException(new FormattableMarkup('%field_id is a reserved value and cannot be used as the machine name of a normal field.', $args));
     }
 
-    $this->fields[$new_field_id] = $this->fields[$old_field_id];
-    unset($this->fields[$old_field_id]);
+    $this->field_settings[$new_field_id] = $this->field_settings[$old_field_id];
+    unset($this->field_settings[$old_field_id]);
 
     $this->resetCaches();
     return $this;
@@ -621,7 +620,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
       throw new SearchApiException(new FormattableMarkup('Cannot remove field with machine name %field_id: field is locked.', $args));
     }
 
-    unset($this->fields[$field_id]);
+    unset($this->field_settings[$field_id]);
 
     $this->resetCaches();
     return $this;
@@ -634,7 +633,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
     $fields = $this->getCache(__FUNCTION__, FALSE);
     if (!$fields) {
       $fields = array();
-      foreach ($this->getFieldSettings() as $key => $field_info) {
+      foreach ($this->field_settings as $key => $field_info) {
         $fields[$key] = Utility::createField($this, $key, $field_info);
       }
     }
@@ -657,7 +656,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
   public function getFieldsByDatasource($datasource_id) {
     $datasource_fields = $this->getCache(__FUNCTION__);
     if (!$datasource_fields) {
-      $datasource_fields = array_fill_keys($this->datasources, array());
+      $datasource_fields = array_fill_keys(array_keys($this->datasource_settings), array());
       $datasource_fields[NULL] = array();
       foreach ($this->getFields() as $field_id => $field) {
         $datasource_fields[$field->getDatasourceId()][$field_id] = $field;
@@ -675,8 +674,8 @@ class Index extends ConfigEntityBase implements IndexInterface {
     $fulltext_fields = $this->getCache(__FUNCTION__);
     if (!$fulltext_fields) {
       $fulltext_fields = array();
-      foreach ($this->getFieldSettings() as $key => $field_info) {
-        if (Utility::isTextType($field_info['type'])) {
+      foreach ($this->getFields() as $key => $field) {
+        if (Utility::isTextType($field->getType())) {
           $fulltext_fields[] = $key;
         }
       }
@@ -688,21 +687,6 @@ class Index extends ConfigEntityBase implements IndexInterface {
   /**
    * {@inheritdoc}
    */
-  public function getFieldSettings() {
-    return $this->fields;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setFieldSettings(array $fields = array()) {
-    $this->fields = $fields;
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getPropertyDefinitions($datasource_id, $alter = TRUE) {
     $alter = $alter ? 1 : 0;
     $properties = $this->getCache(__FUNCTION__);
@@ -767,7 +751,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
    */
   public function indexItems($limit = '-1', $datasource_id = NULL) {
     if ($this->hasValidTracker() && !$this->isReadOnly()) {
-      $tracker = $this->getTracker();
+      $tracker = $this->getTrackerInstance();
       $next_set = $tracker->getRemainingItems($limit, $datasource_id);
       $items = $this->loadItemsMultiple($next_set);
       if ($items) {
@@ -787,13 +771,13 @@ class Index extends ConfigEntityBase implements IndexInterface {
    * {@inheritdoc}
    */
   public function indexSpecificItems(array $search_objects) {
-    if (!$search_objects || $this->read_only) {
+    if (!$search_objects || $this->isReadOnly()) {
       return array();
     }
-    if (!$this->status) {
+    if (!$this->status()) {
       throw new SearchApiException(new FormattableMarkup("Couldn't index values on index %index (index is disabled)", array('%index' => $this->label())));
     }
-    if (empty($this->fields)) {
+    if (!$this->getFields()) {
       throw new SearchApiException(new FormattableMarkup("Couldn't index values on index %index (no fields selected)", array('%index' => $this->label())));
     }
 
@@ -824,12 +808,12 @@ class Index extends ConfigEntityBase implements IndexInterface {
 
     // Items that are rejected should also be deleted from the server.
     if ($rejected_ids) {
-      $this->getServer()->deleteItems($this, $rejected_ids);
+      $this->getServerInstance()->deleteItems($this, $rejected_ids);
     }
 
     $indexed_ids = array();
     if ($items) {
-      $indexed_ids = $this->getServer()->indexItems($this, $items);
+      $indexed_ids = $this->getServerInstance()->indexItems($this, $items);
     }
 
     // Return the IDs of all items that were either successfully indexed or
@@ -838,7 +822,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
 
     if ($processed_ids) {
       if ($this->hasValidTracker()) {
-        $this->getTracker()->trackItemsIndexed($processed_ids);
+        $this->getTrackerInstance()->trackItemsIndexed($processed_ids);
       }
       // Since we've indexed items now, triggering reindexing would have some
       // effect again. Therefore, we reset the flag.
@@ -883,7 +867,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
       foreach ($ids as $id) {
         $item_ids[] = Utility::createCombinedId($datasource_id, $id);
       }
-      $this->getTracker()->$tracker_method($item_ids);
+      $this->getTrackerInstance()->$tracker_method($item_ids);
       if (!$this->isReadOnly() && $this->getOption('index_directly')) {
         try {
           $items = $this->loadItemsMultiple($item_ids);
@@ -907,9 +891,9 @@ class Index extends ConfigEntityBase implements IndexInterface {
       foreach ($ids as $id) {
         $item_ids[] = Utility::createCombinedId($datasource_id, $id);
       }
-      $this->getTracker()->trackItemsDeleted($item_ids);
+      $this->getTrackerInstance()->trackItemsDeleted($item_ids);
       if (!$this->isReadOnly() && $this->isServerEnabled()) {
-        $this->getServer()->deleteItems($this, $item_ids);
+        $this->getServerInstance()->deleteItems($this, $item_ids);
       }
     }
   }
@@ -918,9 +902,9 @@ class Index extends ConfigEntityBase implements IndexInterface {
    * {@inheritdoc}
    */
   public function reindex() {
-    if ($this->status() && !$this->hasReindexed) {
+    if ($this->status() && !$this->isReindexing()) {
       $this->hasReindexed = TRUE;
-      $this->getTracker()->trackAllItemsUpdated();
+      $this->getTrackerInstance()->trackAllItemsUpdated();
       \Drupal::moduleHandler()->invokeAll('search_api_index_reindex', array($this, FALSE));
     }
   }
@@ -932,14 +916,14 @@ class Index extends ConfigEntityBase implements IndexInterface {
     if ($this->status()) {
       // Only invoke the hook if we actually did something.
       $invoke_hook = FALSE;
-      if (!$this->hasReindexed) {
+      if (!$this->isReindexing()) {
         $invoke_hook = TRUE;
         $this->hasReindexed = TRUE;
-        $this->getTracker()->trackAllItemsUpdated();
+        $this->getTrackerInstance()->trackAllItemsUpdated();
       }
       if (!$this->isReadOnly()) {
         $invoke_hook = TRUE;
-        $this->getServer()->deleteAllIndexItems($this);
+        $this->getServerInstance()->deleteAllIndexItems($this);
       }
       if ($invoke_hook) {
         \Drupal::moduleHandler()->invokeAll('search_api_index_reindex', array($this, !$this->isReadOnly()));
@@ -1014,10 +998,10 @@ class Index extends ConfigEntityBase implements IndexInterface {
    * {@inheritdoc}
    */
   public function resetCaches($include_stored = TRUE) {
-    $this->datasourcePlugins = NULL;
-    $this->trackerPlugin = NULL;
+    $this->datasourceInstances = NULL;
+    $this->trackerInstance = NULL;
     $this->serverInstance = NULL;
-    $this->processorPlugins = NULL;
+    $this->processorInstances = NULL;
     $this->cache = array();
     if ($include_stored) {
       Cache::invalidateTags($this->getCacheTags());
@@ -1069,18 +1053,18 @@ class Index extends ConfigEntityBase implements IndexInterface {
 
     // Remove all "locked" and "hidden" flags from all fields of the index. If
     // they are still valid, they should be re-added by the processors.
-    foreach ($this->fields as $field_id => $field_settings) {
-      unset($this->fields[$field_id]['indexed_locked']);
-      unset($this->fields[$field_id]['type_locked']);
-      unset($this->fields[$field_id]['hidden']);
+    foreach ($this->field_settings as $field_id => $field_settings) {
+      unset($this->field_settings[$field_id]['indexed_locked']);
+      unset($this->field_settings[$field_id]['type_locked']);
+      unset($this->field_settings[$field_id]['hidden']);
     }
 
     // We first have to check for locked processors, otherwise their
     // preIndexSave() methods might not be called in the next step.
     foreach ($this->getProcessors(FALSE) as $processor_id => $processor) {
-      if ($processor->isLocked() && !isset($this->processors[$processor_id])) {
-        $this->processors[$processor_id] = array(
-          'processor_id' => $processor_id,
+      if ($processor->isLocked() && !isset($this->processor_settings[$processor_id])) {
+        $this->processor_settings[$processor_id] = array(
+          'plugin_id' => $processor_id,
           'weights' => array(),
           'settings' => array(),
         );
@@ -1105,8 +1089,10 @@ class Index extends ConfigEntityBase implements IndexInterface {
 
     try {
       // Fake an original for inserts to make code cleaner.
+      /** @var \Drupal\search_api\IndexInterface $original */
       $original = $update ? $this->original : static::create(array('status' => FALSE));
 
+      // Reactions for an index that was previously enabled and still is.
       if ($this->status() && $original->status()) {
         // React on possible changes that would require re-indexing, etc.
         $this->reactToServerSwitch($original);
@@ -1114,16 +1100,20 @@ class Index extends ConfigEntityBase implements IndexInterface {
         $this->reactToTrackerSwitch($original);
         $this->reactToProcessorChanges($original);
       }
-      elseif (!$this->status() && $original->status()) {
+
+      // Reactions for an index that is being disabled.
+      if (!$this->status() && $original->status()) {
         if ($this->hasValidTracker()) {
           \Drupal::getContainer()->get('search_api.index_task_manager')->stopTracking($this);
         }
         if ($original->isServerEnabled()) {
-          $original->getServer()->removeIndex($this);
+          $original->getServerInstance()->removeIndex($this);
         }
       }
-      elseif ($this->status() && !$original->status()) {
-        $this->getServer()->addIndex($this);
+
+      // Reactions for an index that is being enabled.
+      if ($this->status() && !$original->status()) {
+        $this->getServerInstance()->addIndex($this);
         if ($this->hasValidTracker()) {
           \Drupal::getContainer()->get('search_api.index_task_manager')->startTracking($this);
         }
@@ -1167,19 +1157,21 @@ class Index extends ConfigEntityBase implements IndexInterface {
    *   The previous version of the index.
    */
   protected function reactToServerSwitch(IndexInterface $original) {
+    assert($original->status() && $this->status(), '::reactToServerSwitch should only be called when the index is enabled.');
+
     if ($this->getServerId() != $original->getServerId()) {
       if ($original->isServerEnabled()) {
-        $original->getServer()->removeIndex($this);
+        $original->getServerInstance()->removeIndex($this);
       }
       if ($this->isServerEnabled()) {
-        $this->getServer()->addIndex($this);
+        $this->getServerInstance()->addIndex($this);
       }
       // When the server changes we also need to trigger a reindex.
       $this->reindex();
     }
     elseif ($this->isServerEnabled()) {
       // Tell the server the index configuration got updated
-      $this->getServer()->updateIndex($this);
+      $this->getServerInstance()->updateIndex($this);
     }
   }
 
@@ -1193,6 +1185,8 @@ class Index extends ConfigEntityBase implements IndexInterface {
    *   The previous version of the index.
    */
   protected function reactToDatasourceSwitch(IndexInterface $original) {
+    assert($original->status() && $this->status(), '::reactToDatasourceSwitch should only be called when the index is enabled.');
+
     $new_datasource_ids = $this->getDatasourceIds();
     $original_datasource_ids = $original->getDatasourceIds();
     if ($new_datasource_ids != $original_datasource_ids) {
@@ -1204,7 +1198,6 @@ class Index extends ConfigEntityBase implements IndexInterface {
     }
   }
 
-
   /**
    * Checks whether the index switched tracker plugin and reacts accordingly.
    *
@@ -1215,7 +1208,9 @@ class Index extends ConfigEntityBase implements IndexInterface {
    *   The previous version of the index.
    */
   protected function reactToTrackerSwitch(IndexInterface $original) {
-    if ($this->tracker != $original->getTrackerId()) {
+    assert($original->status() && $this->status(), '::reactToTrackerSwitch should only be called when the index is enabled.');
+
+    if ($this->getTrackerId() != $original->getTrackerId()) {
       $index_task_manager = \Drupal::getContainer()->get('search_api.index_task_manager');
       if ($original->hasValidTracker()) {
         $index_task_manager->stopTracking($this);
@@ -1233,8 +1228,18 @@ class Index extends ConfigEntityBase implements IndexInterface {
    *   The previous version of the index.
    */
   protected function reactToProcessorChanges(IndexInterface $original) {
-    $original_settings = $original->getProcessorSettings();
-    $new_settings = $this->getProcessorSettings();
+    $orginal_processors = $original->getProcessors();
+    $new_processors = $this->getProcessors();
+
+    $new_settings = array();
+    $original_settings = array();
+
+    foreach ($orginal_processors as $k => $processor) {
+      $original_settings[$k] = $processor->getConfiguration();
+    }
+    foreach ($new_processors as $k => $processor) {
+      $new_settings[$k] = $processor->getConfiguration();
+    }
 
     // Only actually do something when the processor settings are changed.
     if ($original_settings != $new_settings) {
@@ -1291,10 +1296,10 @@ class Index extends ConfigEntityBase implements IndexInterface {
     /** @var \Drupal\search_api\IndexInterface[] $entities */
     foreach ($entities as $index) {
       if ($index->hasValidTracker()) {
-        $index->getTracker()->trackAllItemsDeleted();
+        $index->getTrackerInstance()->trackAllItemsDeleted();
       }
       if ($index->hasValidServer()) {
-        $index->getServer()->removeIndex($index);
+        $index->getServerInstance()->removeIndex($index);
       }
     }
   }
@@ -1325,8 +1330,6 @@ class Index extends ConfigEntityBase implements IndexInterface {
     }
   }
 
-  // @todo Override static load() etc. methods? Measure performance difference.
-
   /**
    * {@inheritdoc}
    */
@@ -1352,7 +1355,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
    *     'CONFIG_DEPENDENCY_KEY' => array(
    *       'always' => array(
    *         'processors' => array(
-   *           'PROCESSOR_ID' => $processor,
+   *           'PLUGIN_ID' => $processor,
    *         ),
    *         'datasources' => array(
    *           'DATASOURCE_ID_1' => $datasource_1,
@@ -1401,7 +1404,7 @@ class Index extends ConfigEntityBase implements IndexInterface {
     // The server needs special treatment, since it is a dependency of the index
     // itself, and not one of its plugins.
     if ($this->hasValidServer()) {
-      $name = $this->getServer()->getConfigDependencyName();
+      $name = $this->getServerInstance()->getConfigDependencyName();
       $dependency_data['config'][$name]['optional']['index'][$this->id] = $this;
     }
 
@@ -1515,18 +1518,23 @@ class Index extends ConfigEntityBase implements IndexInterface {
     // The handling of how we translate plugin changes back to the index varies
     // according to plugin type, unfortunately.
     // First, remove plugins that need to be removed.
-    $this->processors = array_intersect_key($this->processors, $all_plugins['processors']);
-    $this->datasources = array_keys($all_plugins['datasources']);
-    $this->datasource_configs = array_intersect_key($this->datasource_configs, $all_plugins['datasources']);
-    // There always needs to be a tracker.
+    $this->processor_settings = array_intersect_key($this->processor_settings, $all_plugins['processors']);
+    $this->datasource_settings = array_intersect_key($this->datasource_settings, $all_plugins['datasources']);
+    // There always needs to be a tracker but tracker settings are tracker
+    // specific so they can't be moved over to the default tracker.
     if (empty($all_plugins['tracker'])) {
-      $this->tracker = \Drupal::config('search_api.settings')->get('default_tracker');
-      $this->tracker_config = array();
+      $default_tracker = \Drupal::config('search_api.settings')->get('default_tracker');
+      $this->tracker_settings = array(
+        $default_tracker => array(
+          'plugin_id' => $default_tracker,
+          'settings' => array(),
+        )
+      );
     }
     // There also always needs to be a datasource, but here we have no easy way
     // out – if we had to remove all datasources, the operation fails. Return
     // FALSE to indicate this, which will cause the index to be deleted.
-    if (!$this->datasources) {
+    if (!$this->datasource_settings) {
       return FALSE;
     }
 
@@ -1535,13 +1543,13 @@ class Index extends ConfigEntityBase implements IndexInterface {
       foreach ($plugin_configs as $plugin_id => $plugin_config) {
         switch ($plugin_type) {
           case 'processors':
-            $this->processors[$plugin_id]['settings'] = $plugin_config;
+            $this->processor_settings[$plugin_id]['settings'] = $plugin_config;
             break;
           case 'datasources':
-            $this->datasource_configs[$plugin_id] = $plugin_config;
+            $this->datasource_settings[$plugin_id] = $plugin_config;
             break;
           case 'tracker':
-            $this->tracker_config = $plugin_config;
+            $this->tracker_settings = $plugin_config;
             break;
         }
       }
@@ -1564,8 +1572,8 @@ class Index extends ConfigEntityBase implements IndexInterface {
   protected function getAllPlugins() {
     $plugins = array();
 
-    if ($this->hasValidTracker()) {
-      $plugins['tracker'][$this->getTrackerId()] = $this->getTracker();
+    if (!$this->isNew() && $this->hasValidTracker()) {
+      $plugins['tracker'][$this->getTrackerId()] = $this->getTrackerInstance();
     }
     $plugins['processors'] = $this->getProcessors();
     $plugins['datasources'] = $this->getDatasources();
@@ -1590,10 +1598,10 @@ class Index extends ConfigEntityBase implements IndexInterface {
    */
   public function __sleep() {
     $properties = get_object_vars($this);
-    unset($properties['datasourcePlugins']);
-    unset($properties['trackerPlugin']);
+    unset($properties['datasourceInstances']);
+    unset($properties['trackerInstance']);
     unset($properties['serverInstance']);
-    unset($properties['processorPlugins']);
+    unset($properties['processorInstances']);
     unset($properties['cache']);
     return array_keys($properties);
   }
diff --git a/src/Form/IndexFieldsForm.php b/src/Form/IndexFieldsForm.php
index 4b4b2e5..a214251 100644
--- a/src/Form/IndexFieldsForm.php
+++ b/src/Form/IndexFieldsForm.php
@@ -213,7 +213,7 @@ class IndexFieldsForm extends EntityForm {
     $form['description']['#markup'] = $this->t('<p>The data type of a field determines how it can be used for searching and filtering. The boost is used to give additional weight to certain fields, e.g. titles or tags.</p> <p>Whether detailed field types are supported depends on the type of server this index resides on. In any case, fields of type "Fulltext" will always be fulltext-searchable.</p>');
     if ($index->hasValidServer()) {
       $form['description']['#markup'] .= '<p>' . $this->t('Check the <a href=":server-url">' . "server's</a> backend class description for details.",
-          array(':server-url' => $index->getServer()->toUrl('canonical')->toString())) . '</p>';
+          array(':server-url' => $index->getServerInstance()->toUrl('canonical')->toString())) . '</p>';
     }
 
     if ($fields = $index->getFieldsByDatasource(NULL)) {
diff --git a/src/Form/IndexForm.php b/src/Form/IndexForm.php
index 2bfca64..accb9b0 100644
--- a/src/Form/IndexForm.php
+++ b/src/Form/IndexForm.php
@@ -262,7 +262,7 @@ class IndexForm extends EntityForm {
       '#title' => $this->t('Tracker'),
       '#description' => $this->t('Select the type of tracker which should be used for keeping track of item changes.'),
       '#options' => $this->getTrackerPluginManager()->getOptionsList(),
-      '#default_value' => $index->hasValidTracker() ? $index->getTracker()->getPluginId() : key($tracker_options),
+      '#default_value' => $index->hasValidTracker() ? $index->getTrackerId() : key($tracker_options),
       '#required' => TRUE,
       '#disabled' => !$index->isNew(),
       '#ajax' => array(
@@ -313,7 +313,7 @@ class IndexForm extends EntityForm {
       '#description' => $this->t('Only enabled indexes can be used for indexing and searching. This setting will only take effect if the selected server is also enabled.'),
       '#default_value' => $index->status(),
       // Can't enable an index lying on a disabled server or no server at all.
-      '#disabled' => !$index->status() && (!$index->hasValidServer() || !$index->getServer()->status()),
+      '#disabled' => !$index->status() && (!$index->hasValidServer() || !$index->getServerInstance()->status()),
       // @todo This doesn't seem to work and should also hide for disabled
       //   servers. If that works, we can probably remove the last sentence of
       //   the description.
@@ -391,8 +391,8 @@ class IndexForm extends EntityForm {
    *   The index being created or edited.
    */
   public function buildTrackerConfigForm(array &$form, FormStateInterface $form_state, IndexInterface $index) {
-    if ($index->hasValidTracker()) {
-      $tracker = $index->getTracker();
+    if (!$index->isNew() && $index->hasValidTracker()) {
+      $tracker = $index->getTrackerInstance();
       // @todo Create, use and save SubFormState already here, not only in
       //   validate(). Also, use proper subset of $form for first parameter?
       if ($config_form = $tracker->buildConfigurationForm(array(), $form_state)) {
@@ -484,7 +484,7 @@ class IndexForm extends EntityForm {
     //   form structure).
     $tracker_id = $form_state->getValue('tracker', NULL);
     if ($this->originalEntity->getTrackerId() == $tracker_id) {
-      $tracker = $this->originalEntity->getTracker();
+      $tracker = $this->originalEntity->getTrackerInstance();
     }
     else {
       $tracker = $this->trackerPluginManager->createInstance($tracker_id, array('index' => $this->originalEntity));
@@ -532,9 +532,12 @@ class IndexForm extends EntityForm {
       $datasource_form = (!empty($form['datasource_configs'][$datasource_id])) ? $form['datasource_configs'][$datasource_id] : array();
       $datasource_form_state = new SubFormState($form_state, array('datasource_configs', $datasource_id));
       $datasource->submitConfigurationForm($datasource_form, $datasource_form_state);
-      $datasource_configuration[$datasource_id] = $datasource->getConfiguration();
+      $datasource_configuration[$datasource_id] = array(
+        'plugin_id' => $datasource_id,
+        'settings' => $datasource->getConfiguration()
+      );
     }
-    $index->set('datasource_configs', $datasource_configuration);
+    $index->set('datasource_settings', $datasource_configuration);
 
     // Call submitConfigurationForm() for the (possibly new) tracker.
     // @todo It seems if we change the tracker, we would validate/submit the old
@@ -543,8 +546,8 @@ class IndexForm extends EntityForm {
     //   just always be empty (because datasources have their plugin ID in the
     //   form structure).
     $tracker_id = $form_state->getValue('tracker', NULL);
-    if ($this->originalEntity->getTrackerId() == $tracker_id) {
-      $tracker = $this->originalEntity->getTracker();
+    if (!$index->isNew() && $this->originalEntity->getTrackerId() == $tracker_id) {
+      $tracker = $this->originalEntity->getTrackerInstance();
     }
     else {
       $tracker = $this->trackerPluginManager->createInstance($tracker_id, array('index' => $this->originalEntity));
@@ -552,7 +555,13 @@ class IndexForm extends EntityForm {
 
     $tracker_form_state = new SubFormState($form_state, array('tracker_config'));
     $tracker->submitConfigurationForm($form['tracker_config'], $tracker_form_state);
-    $index->set('tracker_config', $tracker->getConfiguration());
+    $tracker_settings = array(
+      $tracker_id => array(
+        'plugin_id' => $tracker_id,
+        'settings' => $tracker->getConfiguration()
+      )
+    );
+    $index->set('tracker_settings', $tracker_settings);
   }
 
   /**
diff --git a/src/Form/IndexProcessorsForm.php b/src/Form/IndexProcessorsForm.php
index d32e5ac..f481df1 100644
--- a/src/Form/IndexProcessorsForm.php
+++ b/src/Form/IndexProcessorsForm.php
@@ -96,8 +96,9 @@ class IndexProcessorsForm extends EntityForm {
       $processors_by_stage[$stage] = $this->entity->getProcessorsByStage($stage, FALSE);
     }
 
-    if ($this->entity->getServer()) {
-      $backend_discouraged_processors = $this->entity->getServer()
+    if ($this->entity->getServerInstance()) {
+      $backend_discouraged_processors = $this->entity
+        ->getServerInstance()
         ->getBackend()
         ->getDiscouragedProcessors();
 
@@ -112,7 +113,7 @@ class IndexProcessorsForm extends EntityForm {
       }
     }
 
-    $processor_settings = $this->entity->getProcessorSettings();
+    $processor_settings = $this->entity->getProcessors(TRUE);
 
     $form['#tree'] = TRUE;
     $form['#attached']['library'][] = 'search_api/drupal.search_api.index-active-formatters';
@@ -171,9 +172,10 @@ class IndexProcessorsForm extends EntityForm {
     foreach ($processors_by_stage as $stage => $processors) {
       /** @var \Drupal\search_api\Processor\ProcessorInterface $processor */
       foreach ($processors as $processor_id => $processor) {
-        $weight = isset($processor_settings[$processor_id]['weights'][$stage])
-          ? $processor_settings[$processor_id]['weights'][$stage]
+        $weight = isset($processor_settings[$processor_id])
+          ? $processor_settings[$processor_id]->getPluginDefinition()['stages'][$stage]
           : $processor->getDefaultWeight($stage);
+
         if ($processor->isHidden()) {
           $form['processors'][$processor_id]['weights'][$stage] = array(
             '#type' => 'value',
@@ -262,7 +264,7 @@ class IndexProcessorsForm extends EntityForm {
         continue;
       }
       $new_settings[$processor_id] = array(
-        'processor_id' => $processor_id,
+        'plugin_id' => $processor_id,
         'weights' => array(),
         'settings' => array(),
       );
@@ -279,10 +281,10 @@ class IndexProcessorsForm extends EntityForm {
 
     // Sort the processors so we won't have unnecessary changes.
     ksort($new_settings);
-    $settings_changed = $new_settings != $this->entity->getProcessorSettings();
+    $settings_changed = $new_settings != $this->entity->get('processor_settings');
     $form_state->set('processors_changed', $settings_changed);
     if ($settings_changed) {
-      $this->entity->setProcessorSettings($new_settings);
+      $this->entity->set('processor_settings', $new_settings);
     }
   }
 
diff --git a/src/Form/IndexStatusForm.php b/src/Form/IndexStatusForm.php
index 640e795..ad42155 100644
--- a/src/Form/IndexStatusForm.php
+++ b/src/Form/IndexStatusForm.php
@@ -65,7 +65,7 @@ class IndexStatusForm extends FormBase {
           'class' => array('container-inline'),
         ),
       );
-      $has_remaining_items = ($index->getTracker()->getRemainingItemsCount() > 0);
+      $has_remaining_items = ($index->getTrackerInstance()->getRemainingItemsCount() > 0);
       $all_value = $this->t('all', array(), array('context' => 'items to index'));
       $limit = array(
         '#type' => 'textfield',
diff --git a/src/IndexBatchHelper.php b/src/IndexBatchHelper.php
index 9da6463..379a9e8 100644
--- a/src/IndexBatchHelper.php
+++ b/src/IndexBatchHelper.php
@@ -137,7 +137,7 @@ class IndexBatchHelper {
     // Get the remaining item count. When no valid tracker is available then
     // the value will be set to zero which will cause the batch process to
     // stop.
-    $remaining_item_count = ($index->hasValidTracker() ? $index->getTracker()->getRemainingItemsCount() : 0);
+    $remaining_item_count = ($index->hasValidTracker() ? $index->getTrackerInstance()->getRemainingItemsCount() : 0);
 
     // Check if an explicit limit needs to be used.
     if ($context['sandbox']['limit'] > -1) {
diff --git a/src/IndexInterface.php b/src/IndexInterface.php
index a435f35..da84764 100644
--- a/src/IndexInterface.php
+++ b/src/IndexInterface.php
@@ -200,7 +200,7 @@ interface IndexInterface extends ConfigEntityInterface {
    * @throws \Drupal\search_api\SearchApiException
    *   Thrown if the tracker couldn't be instantiated.
    */
-  public function getTracker();
+  public function getTrackerInstance();
 
   /**
    * Determines whether this index is lying on a valid server.
@@ -236,10 +236,13 @@ interface IndexInterface extends ConfigEntityInterface {
    * @throws \Drupal\search_api\SearchApiException
    *   Thrown if the server couldn't be loaded.
    */
-  public function getServer();
+  public function getServerInstance();
 
   /**
-   * Sets the server the index is attached to
+   * Sets the server the index is attached to.
+   *
+   * When setting this to NULL, the configured server will be removed from the
+   * index.
    *
    * @param \Drupal\search_api\ServerInterface|null $server
    *   The server to move this index to, or NULL.
@@ -277,24 +280,6 @@ interface IndexInterface extends ConfigEntityInterface {
   public function getProcessorsByStage($stage, $only_enabled = TRUE);
 
   /**
-   * Retrieves this index's processor settings.
-   *
-   * @return array
-   *   An array of processors and their settings.
-   */
-  public function getProcessorSettings();
-
-  /**
-   * Sets this index's processor settings.
-   *
-   * @param array $processors
-   *   An array of processors and their settings.
-   *
-   * @return $this
-   */
-  public function setProcessorSettings(array $processors);
-
-  /**
    * Preprocesses data items for indexing.
    *
    * Lets all enabled processors for this index preprocess the indexed data.
@@ -420,24 +405,6 @@ interface IndexInterface extends ConfigEntityInterface {
   public function getFulltextFields();
 
   /**
-   * Retrieves this index's field settings.
-   *
-   * @return array
-   *   An array of field settings.
-   */
-  public function getFieldSettings();
-
-  /**
-   * Sets this index's field settings.
-   *
-   * @param array $fields
-   *   An array of field settings.
-   *
-   * @return $this
-   */
-  public function setFieldSettings(array $fields);
-
-  /**
    * Retrieves the properties of one of this index's datasources.
    *
    * @param string|null $datasource_id
diff --git a/src/Item/Field.php b/src/Item/Field.php
index 97637ad..abbe268 100644
--- a/src/Item/Field.php
+++ b/src/Item/Field.php
@@ -439,8 +439,7 @@ class Field implements \IteratorAggregate, FieldInterface {
    */
   public function getBoost() {
     if (!isset($this->boost)) {
-      $fields = $this->index->getFieldSettings();
-      $this->boost = isset($fields[$this->fieldIdentifier]['boost']) ? (float) $fields[$this->fieldIdentifier]['boost'] : 1.0;
+      $this->boost = 1.0;
     }
     return $this->boost;
   }
diff --git a/src/Plugin/search_api/processor/RenderedItem.php b/src/Plugin/search_api/processor/RenderedItem.php
index a277fc3..032be42 100644
--- a/src/Plugin/search_api/processor/RenderedItem.php
+++ b/src/Plugin/search_api/processor/RenderedItem.php
@@ -284,7 +284,8 @@ class RenderedItem extends ProcessorPluginBase {
         '%processor' => $this->label(),
         '@count' => $unset_view_modes,
       );
-      $this->getLogger()->warning('Warning: While indexing items on search index %index, @count item(s) did not have a view mode configured for the %processor processor.', $context);
+      $this->getLogger()
+        ->warning('Warning: While indexing items on search index %index, @count item(s) did not have a view mode configured for the %processor processor.', $context);
     }
 
     // Restore the original user.
diff --git a/src/Plugin/views/argument/SearchApiMoreLikeThis.php b/src/Plugin/views/argument/SearchApiMoreLikeThis.php
index f39c8b0..bfe03e3 100644
--- a/src/Plugin/views/argument/SearchApiMoreLikeThis.php
+++ b/src/Plugin/views/argument/SearchApiMoreLikeThis.php
@@ -69,7 +69,7 @@ class SearchApiMoreLikeThis extends SearchApiArgument {
    */
   public function query($group_by = FALSE) {
     try {
-      $server = $this->query->getIndex()->getServer();
+      $server = $this->query->getIndex()->getServerInstance();
       if (!$server->supportsFeature('search_api_mlt')) {
         $backend_id = $server->getBackendId();
         \Drupal::logger('search_api')->error('The search backend "@backend_id" does not offer "More like this" functionality.',
diff --git a/src/Query/Query.php b/src/Query/Query.php
index eb22371..53bbe60 100644
--- a/src/Query/Query.php
+++ b/src/Query/Query.php
@@ -318,7 +318,7 @@ class Query implements QueryInterface {
     $this->preExecute();
 
     // Execute query.
-    $response = $this->index->getServer()->search($this);
+    $response = $this->index->getServerInstance()->search($this);
 
     // Postprocess the search results.
     $this->postExecute($response);
diff --git a/src/Task/IndexTaskManager.php b/src/Task/IndexTaskManager.php
index db1b5b8..4cfafcb 100644
--- a/src/Task/IndexTaskManager.php
+++ b/src/Task/IndexTaskManager.php
@@ -99,7 +99,7 @@ class IndexTaskManager implements IndexTaskManagerInterface {
             $item_ids[] = Utility::createCombinedId($datasource_id, $raw_id);
           }
           $added = count($item_ids);
-          $index->getTracker()->trackItemsInserted($item_ids);
+          $index->getTrackerInstance()->trackItemsInserted($item_ids);
         }
       }
     }
@@ -195,7 +195,7 @@ class IndexTaskManager implements IndexTaskManagerInterface {
     if (!isset($datasource_ids)) {
       $this->state->delete($this->getIndexStateKey($index));
       if ($valid_tracker) {
-        $index->getTracker()->trackAllItemsDeleted();
+        $index->getTrackerInstance()->trackAllItemsDeleted();
       }
       return;
     }
@@ -211,7 +211,7 @@ class IndexTaskManager implements IndexTaskManagerInterface {
     foreach ($datasource_ids as $datasource_id) {
       unset($index_state['pages'][$datasource_id]);
       if ($valid_tracker) {
-        $index->getTracker()->trackAllItemsDeleted($datasource_id);
+        $index->getTrackerInstance()->trackAllItemsDeleted($datasource_id);
       }
     }
 
diff --git a/src/Task/ServerTaskManager.php b/src/Task/ServerTaskManager.php
index d1f7e01..f0a7e22 100644
--- a/src/Task/ServerTaskManager.php
+++ b/src/Task/ServerTaskManager.php
@@ -50,9 +50,17 @@ class ServerTaskManager implements ServerTaskManagerInterface {
    */
   public function execute(ServerInterface $server = NULL) {
     $select = $this->database->select('search_api_task', 't');
+    // Only retrieve tasks we can handle.
+    $allowed_tasks = array(
+      'addIndex',
+      'updateIndex',
+      'removeIndex',
+      'deleteItems',
+      'deleteAllIndexItems'
+    );
     $select->fields('t')
-      // Only retrieve tasks we can handle.
-      ->condition('t.type', array('addIndex', 'updateIndex', 'removeIndex', 'deleteItems', 'deleteAllIndexItems'), 'IN');
+      ->condition('t.type', $allowed_tasks, 'IN');
+
     if ($server) {
       if (!$server->status()) {
         return FALSE;
diff --git a/src/Tests/IntegrationTest.php b/src/Tests/IntegrationTest.php
index a14f24d..bf81971 100644
--- a/src/Tests/IntegrationTest.php
+++ b/src/Tests/IntegrationTest.php
@@ -98,6 +98,53 @@ class IntegrationTest extends WebTestBase {
   }
 
   /**
+   * Test what happens when an index has an integer as id/label.
+   *
+   * This needs to be in a seperate index because we also want to see what
+   * happens with the content and we don't want to mess with the content entity
+   * tracking of the other index.
+   */
+  public function testIntegerIndex() {
+    $this->drupalLogin($this->adminUser);
+    $this->getTestServer();
+
+    $this->drupalCreateNode(array('type' => 'article'));
+    $this->drupalCreateNode(array('type' => 'article'));
+
+    $this->drupalGet('admin/config/search/search-api/add-index');
+
+    $this->indexId = 123;
+    $edit = array(
+      'name' => $this->indexId,
+      'id' => $this->indexId,
+      'status' => 1,
+      'description' => 'test Index:: 123~',
+      'server' => 'webtest_server',
+      'datasources[]' => array('entity:node'),
+    );
+    $this->drupalPostForm(NULL, $edit, $this->t('Save'));
+    $this->assertText($this->t('The index was successfully saved.'));
+    $this->assertText($this->t('Successfully tracked @count items for this index.', array('@count' => 2)));
+    $this->assertEqual(2, $this->countTrackedItems());
+
+    $this->enableAllProcessors();
+    $this->checkFieldLabels();
+
+    $this->addFieldsToIndex();
+    $this->removeFieldsFromIndex();
+
+    $this->configureFilter();
+    $this->configureFilterPage();
+    $this->checkProcessorChanges();
+    $this->changeProcessorFieldBoost();
+
+    $this->setReadOnly();
+    $this->disableEnableIndex();
+    $this->changeIndexDatasource();
+    $this->changeIndexServer();
+  }
+
+  /**
    * Tests creating a search server via the UI.
    */
   protected function createServer($server_id = '_test_server') {
@@ -169,7 +216,6 @@ class IntegrationTest extends WebTestBase {
     $this->assertText($this->t('@name field is required.', array('@name' => $this->t('Machine-readable name'))));
     $this->assertText($this->t('@name field is required.', array('@name' => $this->t('Data sources'))));
 
-
     $edit = array(
       'name' => $index_name,
       'id' => $this->indexId,
@@ -382,7 +428,9 @@ class IntegrationTest extends WebTestBase {
    *   The number of tracked items in the test index.
    */
   protected function countTrackedItems() {
-    return $this->getIndex()->getTracker()->getTotalItemsCount();
+    return $this->getIndex()
+      ->getTrackerInstance()
+      ->getTotalItemsCount();
   }
 
   /**
@@ -392,7 +440,9 @@ class IntegrationTest extends WebTestBase {
    *   The number of unindexed items in the test index.
    */
   protected function countRemainingItems() {
-    return $this->getIndex()->getTracker()->getRemainingItemsCount();
+    return $this->getIndex()
+      ->getTrackerInstance()
+      ->getRemainingItemsCount();
   }
 
   /**
@@ -723,7 +773,7 @@ class IntegrationTest extends WebTestBase {
 
     $this->drupalPostForm($index_path, array(), $this->t('Index now'));
 
-    $remaining_after = $index->getTracker()->getRemainingItemsCount();
+    $remaining_after = $index->getTrackerInstance()->getRemainingItemsCount();
     $this->assertEqual(0, $remaining_after, 'Items were indexed after removing the "read only" flag.');
 
   }
diff --git a/src/Tests/LanguageIntegrationTest.php b/src/Tests/LanguageIntegrationTest.php
index 5dfec22..0dc654e 100644
--- a/src/Tests/LanguageIntegrationTest.php
+++ b/src/Tests/LanguageIntegrationTest.php
@@ -128,7 +128,7 @@ class LanguageIntegrationTest extends WebTestBase {
   protected function countTrackedItems() {
     /** @var \Drupal\search_api\IndexInterface $index */
     $index = Index::load($this->indexId);
-    return $index->getTracker()->getTotalItemsCount();
+    return $index->getTrackerInstance()->getTotalItemsCount();
   }
 
   /**
diff --git a/src/Tests/Processor/ContentAccessTest.php b/src/Tests/Processor/ContentAccessTest.php
index b301cd4..1b443c5 100644
--- a/src/Tests/Processor/ContentAccessTest.php
+++ b/src/Tests/Processor/ContentAccessTest.php
@@ -109,7 +109,23 @@ class ContentAccessTest extends ProcessorTestBase {
     $this->nodes[2]->save();
 
     // Also index users, to verify that they are unaffected by the processor.
-    $this->index->set('datasources', array('entity:comment', 'entity:node', 'entity:user'));
+    $this->index->set(
+      'datasource_settings',
+      array(
+        'entity:comment' => array(
+          'plugin_id' => 'entity:comment',
+          'settings' => array(),
+        ),
+        'entity:node' => array(
+          'plugin_id' => 'entity:node',
+          'settings' => array(),
+        ),
+        'entity:user' => array(
+          'plugin_id' => 'entity:user',
+          'settings' => array(),
+        )
+      )
+    );
     $this->index->save();
 
     \Drupal::getContainer()->get('search_api.index_task_manager')->addItemsAll($this->index);
@@ -128,6 +144,7 @@ class ContentAccessTest extends ProcessorTestBase {
     $query = Utility::createQuery($this->index);
     $result = $query->execute();
 
+    $this->assertEqual($result->getResultCount(), 4);
     $this->assertResults($result, array('user' => array(0), 'comment' => array(0), 'node' => array(0, 1)));
   }
 
diff --git a/src/Tests/Processor/ProcessorIntegrationTest.php b/src/Tests/Processor/ProcessorIntegrationTest.php
index ad617c8..2d6bf7a 100644
--- a/src/Tests/Processor/ProcessorIntegrationTest.php
+++ b/src/Tests/Processor/ProcessorIntegrationTest.php
@@ -32,7 +32,12 @@ class ProcessorIntegrationTest extends WebTestBase {
       'name' => 'Test index',
       'id' => $this->indexId,
       'status' => 1,
-      'datasources' => array('entity:node'),
+      'datasource_settings' => array(
+        'entity:node' => array(
+          'plugin_id' => 'entity:node',
+          'settings' => array(),
+        )
+      ),
     ))->save();
   }
 
@@ -129,7 +134,6 @@ class ProcessorIntegrationTest extends WebTestBase {
     // testing environment regarding the YAML in the "tags" setting.
     $edit = array(
       'status[html_filter]' => 1,
-      'processors[html_filter][settings][fields][search_api_language]' => FALSE,
       'processors[html_filter][settings][title]' => FALSE,
       'processors[html_filter][settings][alt]' => FALSE,
       'processors[html_filter][settings][tags]' => 'h1: 10'
@@ -142,11 +146,6 @@ class ProcessorIntegrationTest extends WebTestBase {
    */
   public function checkIgnoreCaseIntegration() {
     $this->enableProcessor('ignorecase');
-
-    $edit = array(
-      'processors[ignorecase][settings][fields][search_api_language]' => FALSE,
-    );
-    $this->editSettingsForm($edit, 'ignorecase');
   }
 
   /**
@@ -156,7 +155,6 @@ class ProcessorIntegrationTest extends WebTestBase {
     $this->enableProcessor('ignore_character');
 
     $edit = array(
-      'processors[ignore_character][settings][fields][search_api_language]' => FALSE,
       'processors[ignore_character][settings][ignorable]' => '[¿¡!?,.]',
       'processors[ignore_character][settings][strip][character_sets][Cc]' => TRUE,
     );
@@ -168,10 +166,9 @@ class ProcessorIntegrationTest extends WebTestBase {
    */
   public function checkLanguageIntegration() {
     $index = $this->loadIndex();
-    $processors = $index->getProcessorSettings();
+    $processors = $index->getProcessors();
     $this->assertTrue(!empty($processors['language']), 'The "language" processor is enabled by default.');
-    unset($processors['language']);
-    $index->setProcessorSettings($processors)->save();
+    $index->removeProcessor('language');
     $processors = $this->loadIndex()->getProcessors();
     $this->assertTrue(!empty($processors['language']), 'The "language" processor cannot be disabled.');
   }
@@ -228,11 +225,6 @@ class ProcessorIntegrationTest extends WebTestBase {
    */
   public function checkTransliterationIntegration() {
     $this->enableProcessor('transliteration');
-
-    $edit = array(
-      'processors[transliteration][settings][fields][search_api_language]' => FALSE,
-    );
-    $this->editSettingsForm($edit, 'transliteration');
   }
 
   /**
@@ -240,10 +232,9 @@ class ProcessorIntegrationTest extends WebTestBase {
    */
   public function checkUrlFieldIntegration() {
     $index = $this->loadIndex();
-    $processors = $index->getProcessorSettings();
+    $processors = $index->getProcessors();
     $this->assertTrue(!empty($processors['add_url']), 'The "Add URL" processor is enabled by default.');
-    unset($processors['add_url']);
-    $index->setProcessorSettings($processors)->save();
+    $index->removeProcessor('add_url');
     $processors = $this->loadIndex()->getProcessors();
     $this->assertTrue(!empty($processors['add_url']), 'The "Add URL" processor cannot be disabled.');
   }
diff --git a/src/Tests/Processor/ProcessorTestBase.php b/src/Tests/Processor/ProcessorTestBase.php
index 2809c31..cc93553 100644
--- a/src/Tests/Processor/ProcessorTestBase.php
+++ b/src/Tests/Processor/ProcessorTestBase.php
@@ -9,6 +9,7 @@ namespace Drupal\search_api\Tests\Processor;
 
 use Drupal\search_api\Entity\Index;
 use Drupal\search_api\Entity\Server;
+use Drupal\search_api\Item\Field;
 use Drupal\search_api\Utility;
 use Drupal\system\Tests\Entity\EntityUnitTestBase;
 
@@ -87,29 +88,44 @@ abstract class ProcessorTestBase extends EntityUnitTestBase {
       'id' => 'index',
       'name' => 'Index name',
       'status' => TRUE,
-      'datasources' => array('entity:comment', 'entity:node'),
-      'server' => 'server',
-      'tracker' => 'default',
-    ));
-    $this->index->setServer($this->server);
-    $this->index->setFieldSettings(array(
-      'subject' => array(
-        'label' => 'Subject',
-        'type' => 'text',
-        'datasource_id' => 'entity:comment',
-        'property_path' => 'subject',
+      'datasource_settings' => array(
+        'entity:comment' => array(
+          'plugin_id' => 'entity:comment',
+          'settings' => array(),
+        ),
+        'entity:node' => array(
+          'plugin_id' => 'entity:node',
+          'settings' => array(),
+        ),
       ),
-      'title' => array(
-        'label' => 'Title',
-        'type' => 'text',
-        'datasource_id' => 'entity:node',
-        'property_path' => 'title',
+      'server' => 'server',
+      'tracker_settings' => array(
+        'default' => array(
+          'plugin_id' => 'default',
+          'settings' => array()
+        )
       ),
     ));
+    $this->index->setServer($this->server);
+
+    $subject_field = new Field($this->index, 'subject');
+    $subject_field->setType('text');
+    $subject_field->setLabel('Subject');
+    $subject_field->setDatasourceId('entity:comment');
+    $subject_field->setPropertyPath('subject');
+    $this->index->addField($subject_field);
+
+    $title_field = new Field($this->index, 'title');
+    $title_field->setType('text');
+    $title_field->setLabel('Title');
+    $title_field->setDatasourceId('entity:node');
+    $title_field->setPropertyPath('title');
+    $this->index->addField($title_field);
+
     if ($processor) {
-      $this->index->setProcessorSettings(array(
+      $this->index->set('processor_settings', array(
         $processor => array(
-          'processor_id' => $processor,
+          'plugin_id' => $processor,
           'weights' => array(),
           'settings' => array(),
         ),
diff --git a/src/Tests/Processor/RenderedItemTest.php b/src/Tests/Processor/RenderedItemTest.php
index 8a920e4..6ff3751 100644
--- a/src/Tests/Processor/RenderedItemTest.php
+++ b/src/Tests/Processor/RenderedItemTest.php
@@ -10,6 +10,8 @@ namespace Drupal\search_api\Tests\Processor;
 use Drupal\Core\TypedData\DataDefinition;
 use Drupal\node\Entity\Node;
 use Drupal\node\Entity\NodeType;
+use Drupal\search_api\Item\Field;
+use Drupal\search_api\Item\FieldInterface;
 use Drupal\search_api\Utility;
 use Drupal\user\Entity\Role;
 use Drupal\user\Entity\User;
@@ -49,6 +51,11 @@ class RenderedItemTest extends ProcessorTestBase {
     $this->installSchema('system', array('router'));
     \Drupal::service('router.builder')->rebuild();
 
+    $rendered_item_field = new Field($this->index, 'rendered_item');
+    $rendered_item_field->setPropertyPath('rendered_item');
+    $rendered_item_field->setType('text');
+    $this->index->addField($rendered_item_field);
+
     // Create a node type for testing.
     $type = NodeType::create(array(
       'type' => 'page',
@@ -115,6 +122,29 @@ class RenderedItemTest extends ProcessorTestBase {
   }
 
   /**
+   * Tests that the processor is added correctly.
+   */
+  public function testAddProcessor() {
+    $processors = $this->index->getProcessors();
+    $this->assertTrue(array_key_exists('rendered_item', $processors), 'Processor successfully added.');
+
+    $items = array();
+    foreach ($this->nodes as $node) {
+      $items[] = array(
+        'datasource' => 'entity:node',
+        'item' => $node->getTypedData(),
+        'item_id' => $node->id(),
+        'text' => 'node text' . $node->id(),
+      );
+    }
+    $items = $this->generateItems($items);
+
+    foreach ($items as $item) {
+      $this->assertTrue(array_key_exists('rendered_item', $item->getFields()), 'Field successfully added.');
+    }
+  }
+
+  /**
    * Tests whether the rendered_item field is correctly filled by the processor.
    */
   public function testPreprocessIndexItems() {
diff --git a/src/Tests/WebTestBase.php b/src/Tests/WebTestBase.php
index 8b85ea6..72bb5e2 100644
--- a/src/Tests/WebTestBase.php
+++ b/src/Tests/WebTestBase.php
@@ -169,7 +169,18 @@ abstract class WebTestBase extends SimpletestWebTestBase {
         'name' => $name,
         'description' => $name . ' description',
         'server' => $server_id,
-        'datasources' => array($datasource_id),
+        'datasource_settings' => array(
+          $datasource_id => array(
+            'plugin_id' => $datasource_id,
+            'settings' => array(),
+          )
+        ),
+        'tracker_settings' => array(
+          'default' => array(
+            'plugin_id' => 'default',
+            'settings' => array(),
+          )
+        ),
       ));
       $index->save();
       $this->indexId = $index->id();
diff --git a/src/UnsavedIndexConfiguration.php b/src/UnsavedIndexConfiguration.php
index 8fe07be..bb93c57 100644
--- a/src/UnsavedIndexConfiguration.php
+++ b/src/UnsavedIndexConfiguration.php
@@ -249,8 +249,8 @@ class UnsavedIndexConfiguration implements IndexInterface, UnsavedConfigurationI
   /**
    * {@inheritdoc}
    */
-  public function getTracker() {
-    return $this->entity->getTracker();
+  public function getTrackerInstance() {
+    return $this->entity->getTrackerInstance();
   }
 
   /**
@@ -277,8 +277,8 @@ class UnsavedIndexConfiguration implements IndexInterface, UnsavedConfigurationI
   /**
    * {@inheritdoc}
    */
-  public function getServer() {
-    return $this->entity->getServer();
+  public function getServerInstance() {
+    return $this->entity->getServerInstance();
   }
 
   /**
diff --git a/src/Utility.php b/src/Utility.php
index 15dccc4..34a4717 100644
--- a/src/Utility.php
+++ b/src/Utility.php
@@ -153,7 +153,7 @@ class Utility {
     if (empty(static::$dataTypeFallbackMapping[$index_id])) {
       $server = NULL;
       try {
-        $server = $index->getServer();
+        $server = $index->getServerInstance();
       }
       catch (SearchApiException $e) {
         // If the server isn't available, just ignore it here and return all
diff --git a/tests/search_api_test_backend/src/Plugin/search_api/backend/TestBackend.php b/tests/search_api_test_backend/src/Plugin/search_api/backend/TestBackend.php
index 5032989..57ced24 100644
--- a/tests/search_api_test_backend/src/Plugin/search_api/backend/TestBackend.php
+++ b/tests/search_api_test_backend/src/Plugin/search_api/backend/TestBackend.php
@@ -128,6 +128,18 @@ class TestBackend extends BackendPluginBase {
     $results = Utility::createSearchResultSet($query);
     $result_items = array();
     $datasources = $query->getIndex()->getDatasources();
+
+    // Searching on an index without datasources is useless, return an empty
+    // result set and log this so the admin knows what's going on.
+    if ($datasources === array()) {
+      $logger = \Drupal::getContainer()
+        ->get('logger.factory')
+        ->get('search_api');
+      $logger->notice($this->t('Tried searching on an index with no datasources.'));
+
+      $results->setResultCount(0);
+      return $results;
+    }
     /** @var \Drupal\search_api\Datasource\DatasourceInterface $datasource */
     $datasource = reset($datasources);
     $datasource_id = $datasource->getPluginId();
diff --git a/tests/search_api_test_db/config/install/search_api.index.database_search_index.yml b/tests/search_api_test_db/config/install/search_api.index.database_search_index.yml
index 4f42d29..72e1971 100644
--- a/tests/search_api_test_db/config/install/search_api.index.database_search_index.yml
+++ b/tests/search_api_test_db/config/install/search_api.index.database_search_index.yml
@@ -2,7 +2,7 @@ id: database_search_index
 name: 'Test index'
 description: 'An index used for testing'
 read_only: false
-fields:
+field_settings:
   id:
     label: ID
     type: integer
@@ -38,27 +38,30 @@ fields:
     label: 'Item language'
     type: string
     property_path: search_api_language
-    index_locked: true
+    indexed_locked: true
     type_locked: true
-processors:
+processor_settings:
   add_url:
-    processor_id: add_url
+    plugin_id: add_url
     weights:
       preprocess_index: -30
     settings: {  }
   language:
-    processor_id: language
+    plugin_id: language
     weights:
       preprocess_index: -50
     settings: {  }
 options:
   cron_limit: -1
   index_directly: false
-datasources:
-  - 'entity:entity_test'
-datasource_configs: {  }
-tracker: default
-tracker_config: {  }
+datasource_settings:
+  'entity:entity_test':
+    plugin_id: 'entity:entity_test'
+    settings: {}
+tracker_settings:
+  default:
+    plugin_id: default
+    settings: {}
 server: database_search_server
 status: true
 langcode: en
diff --git a/tests/search_api_test_dependencies/src/Plugin/search_api/datasource/TestDatasource.php b/tests/search_api_test_dependencies/src/Plugin/search_api/datasource/TestDatasource.php
index 800f18f..58056ac 100644
--- a/tests/search_api_test_dependencies/src/Plugin/search_api/datasource/TestDatasource.php
+++ b/tests/search_api_test_dependencies/src/Plugin/search_api/datasource/TestDatasource.php
@@ -29,7 +29,10 @@ class TestDatasource extends DatasourcePluginBase {
    * {@inheritdoc}
    */
   public function calculateDependencies() {
-    return $this->configuration;
+    if (isset($this->configuration['settings'])) {
+      return $this->configuration['settings'];
+    }
+    return array();
   }
 
   /**
diff --git a/tests/search_api_test_dependencies/src/Plugin/search_api/processor/TestProcessor.php b/tests/search_api_test_dependencies/src/Plugin/search_api/processor/TestProcessor.php
index 5ce230c..01136fa 100644
--- a/tests/search_api_test_dependencies/src/Plugin/search_api/processor/TestProcessor.php
+++ b/tests/search_api_test_dependencies/src/Plugin/search_api/processor/TestProcessor.php
@@ -21,7 +21,10 @@ class TestProcessor extends ProcessorPluginBase {
    * {@inheritdoc}
    */
   public function calculateDependencies() {
-    return $this->configuration;
+    if (isset($this->configuration)) {
+      return $this->configuration;
+    }
+    return array();
   }
 
   /**
diff --git a/tests/search_api_test_dependencies/src/Plugin/search_api/tracker/TestTracker.php b/tests/search_api_test_dependencies/src/Plugin/search_api/tracker/TestTracker.php
index 6ac77d4..dd43a65 100644
--- a/tests/search_api_test_dependencies/src/Plugin/search_api/tracker/TestTracker.php
+++ b/tests/search_api_test_dependencies/src/Plugin/search_api/tracker/TestTracker.php
@@ -21,7 +21,10 @@ class TestTracker extends BasicTracker {
    * {@inheritdoc}
    */
   public function calculateDependencies() {
-    return $this->configuration;
+    if (isset($this->configuration)) {
+      return $this->configuration;
+    }
+    return array();
   }
 
   /**
diff --git a/tests/src/Kernel/CliTest.php b/tests/src/Kernel/CliTest.php
index 70fd5cc..96109ad 100644
--- a/tests/src/Kernel/CliTest.php
+++ b/tests/src/Kernel/CliTest.php
@@ -94,15 +94,25 @@ class CliTest extends KernelTestBase {
       'name' => 'Test index',
       'id' => 'index',
       'status' => 1,
-      'datasources' => array('entity:entity_test'),
-      'tracker' => 'default',
+      'datasource_settings' => array(
+        'entity:entity_test' => array(
+          'plugin_id' => 'entity:entity_test',
+          'settings' => array()
+        )
+      ),
+      'tracker_settings' => array(
+        'default' => array(
+          'plugin_id' => 'default',
+          'settings' => array()
+        )
+      ),
       'server' => $this->server->id(),
       'options' => array('index_directly' => TRUE),
     ));
     $index->save();
 
-    $total_items = $index->getTracker()->getTotalItemsCount();
-    $indexed_items = $index->getTracker()->getIndexedItemsCount();
+    $total_items = $index->getTrackerInstance()->getTotalItemsCount();
+    $indexed_items = $index->getTrackerInstance()->getIndexedItemsCount();
 
     $this->assertEquals($total_items, 2, 'The 2 items are tracked.');
     $this->assertEquals($indexed_items, 0, 'No items are indexed');
@@ -122,8 +132,8 @@ class CliTest extends KernelTestBase {
       'category' => 'item_category'
     ))->save();
 
-    $total_items = $index->getTracker()->getTotalItemsCount();
-    $indexed_items = $index->getTracker()->getIndexedItemsCount();
+    $total_items = $index->getTrackerInstance()->getTotalItemsCount();
+    $indexed_items = $index->getTrackerInstance()->getIndexedItemsCount();
 
     $this->assertEquals($total_items, 4, 'All 4 items are tracked.');
     $this->assertEquals($indexed_items, 2, '2 items are indexed');
diff --git a/tests/src/Kernel/DependencyRemovalTest.php b/tests/src/Kernel/DependencyRemovalTest.php
index 61a7da3..2c23e62 100644
--- a/tests/src/Kernel/DependencyRemovalTest.php
+++ b/tests/src/Kernel/DependencyRemovalTest.php
@@ -48,6 +48,9 @@ class DependencyRemovalTest extends KernelTestBase {
   public function setUp() {
     parent::setUp();
 
+    $this->installSchema('user', array('users_data'));
+    $this->installEntitySchema('user');
+
     // The server tasks manager is needed when removing a server.
     $mock = $this->getMock('Drupal\search_api\Task\ServerTaskManagerInterface');
     $this->container->set('search_api.server_task_manager', $mock);
@@ -57,9 +60,17 @@ class DependencyRemovalTest extends KernelTestBase {
     $this->index = Index::create(array(
       'id' => 'test_index',
       'name' => 'Test index',
-      'tracker' => 'default',
-      'datasources' => array(
-        'entity:user',
+      'tracker_settings' => array(
+        'default' => array(
+          'plugin_id' => 'default',
+          'settings' => array(),
+        )
+      ),
+      'datasource_settings' => array(
+        'entity:user' => array(
+          'plugin_id' => 'entity:user',
+          'settings' => array(),
+        )
       ),
     ));
 
@@ -173,17 +184,21 @@ class DependencyRemovalTest extends KernelTestBase {
     // server.
     $dependency_key = $this->dependency->getConfigDependencyKey();
     $dependency_name = $this->dependency->getConfigDependencyName();
-    $this->index->set('datasources', array(
-      'entity:user',
-      'search_api_test_dependencies',
-    ));
-    $this->index->set('datasource_configs', array(
+    $datasource_settings = array(
+      'entity:user' => array(
+        'plugin_id' => 'entity:user',
+        'settings' => array(),
+      ),
       'search_api_test_dependencies' => array(
-        $dependency_key => array(
-          $dependency_name,
+        'plugin_id' => 'search_api_test_dependencies',
+        'settings' => array(
+          $dependency_key => array(
+            $dependency_name,
+          ),
         ),
-      ),
-    ));
+      )
+    );
+    $this->index->set('datasource_settings', $datasource_settings);
     $this->index->save();
 
     // Check the dependencies were calculated correctly.
@@ -210,15 +225,14 @@ class DependencyRemovalTest extends KernelTestBase {
 
     // Depending on whether the plugin should have removed the dependency or
     // not, make sure the right action was taken.
-    $datasources = $this->index->get('datasources');
-    $datasource_configs = $this->index->get('datasource_configs');
+    $datasource_settings = $this->index->get('datasource_settings');
+
     if ($remove_dependency) {
-      $this->assertContains('search_api_test_dependencies', $datasources, 'Datasource not removed');
-      $this->assertEmpty($datasource_configs['search_api_test_dependencies'], 'Datasource settings adapted');
+      $this->assertArrayHasKey('search_api_test_dependencies', $datasource_settings, 'Datasource not removed');
+      $this->assertEmpty($datasource_settings['search_api_test_dependencies'], 'Datasource settings adapted');
     }
     else {
-      $this->assertNotContains('search_api_test_dependencies', $datasources, 'Datasource removed');
-      $this->assertArrayNotHasKey('search_api_test_dependencies', $datasource_configs, 'Datasource config removed');
+      $this->assertArrayNotHasKey('search_api_test_dependencies', $datasource_settings, 'Datasource config removed');
     }
   }
 
@@ -231,15 +245,15 @@ class DependencyRemovalTest extends KernelTestBase {
     // server.
     $dependency_key = $this->dependency->getConfigDependencyKey();
     $dependency_name = $this->dependency->getConfigDependencyName();
-    $this->index->set('datasources', array(
-      'search_api_test_dependencies',
-    ));
-    $this->index->set('datasource_configs', array(
+    $this->index->set('datasource_settings', array(
       'search_api_test_dependencies' => array(
-        $dependency_key => array(
-          $dependency_name,
+        'plugin_id' => 'search_api_test_dependencies',
+        'settings' => array(
+          $dependency_key => array(
+            $dependency_name,
+          ),
         ),
-      ),
+      )
     ));
     $this->index->save();
 
@@ -275,9 +289,9 @@ class DependencyRemovalTest extends KernelTestBase {
     // server.
     $dependency_key = $this->dependency->getConfigDependencyKey();
     $dependency_name = $this->dependency->getConfigDependencyName();
-    $this->index->set('processors', array(
+    $this->index->set('processor_settings', array(
       'search_api_test_dependencies' => array(
-        'processor_id' => 'search_api_test_dependencies',
+        'plugin_id' => 'search_api_test_dependencies',
         'settings' => array(
           $dependency_key => array(
             $dependency_name,
@@ -311,13 +325,13 @@ class DependencyRemovalTest extends KernelTestBase {
 
     // Depending on whether the plugin should have removed the dependency or
     // not, make sure the right action was taken.
-    $processors = $this->index->get('processors');
+    $processor_settings = $this->index->get('processor_settings');
     if ($remove_dependency) {
-      $this->assertArrayHasKey('search_api_test_dependencies', $processors, 'Processor not removed');
-      $this->assertEmpty($processors['search_api_test_dependencies']['settings'], 'Processor settings adapted');
+      $this->assertArrayHasKey('search_api_test_dependencies', $processor_settings, 'Processor not removed');
+      $this->assertEmpty($processor_settings['search_api_test_dependencies']['settings'], 'Processor settings adapted');
     }
     else {
-      $this->assertArrayNotHasKey('search_api_test_dependencies', $processors, 'Processor removed');
+      $this->assertArrayNotHasKey('search_api_test_dependencies', $processor_settings, 'Processor removed');
     }
   }
 
@@ -331,17 +345,23 @@ class DependencyRemovalTest extends KernelTestBase {
    * @dataProvider dependencyTestDataProvider
    */
   public function testTrackerDependency($remove_dependency) {
+    // Set the server on the index and save that, too.
+    $this->index->set('server', $this->dependency->id());
+
     // Set the tracker for the index and save it. The tracker configuration
     // contains the dependencies it will return – in our case, we use the test
     // server.
     $dependency_key = $this->dependency->getConfigDependencyKey();
     $dependency_name = $this->dependency->getConfigDependencyName();
-    $this->index->set('tracker', 'search_api_test_dependencies');
-    $this->index->set('tracker_config', array(
-      $dependency_key => array(
-        $dependency_name,
-      ),
+    $tracker_settings = array('search_api_test_dependencies' => array(
+      'plugin_id' => 'search_api_test_dependencies',
+      'settings' => array(
+        $dependency_key => array(
+          $dependency_name,
+        ),
+      )
     ));
+    $this->index->set('tracker_settings', $tracker_settings);
     $this->index->save();
 
     // Check the dependencies were calculated correctly.
@@ -353,13 +373,12 @@ class DependencyRemovalTest extends KernelTestBase {
     // \Drupal\search_api_test_dependencies\Plugin\search_api\tracker\TestTracker::onDependencyRemoval().
     $key = 'search_api_test_dependencies.tracker.remove';
     \Drupal::state()->set($key, $remove_dependency);
+
     // If the index resets the tracker, it needs to know the ID of the default
     // tracker.
-    if (!$remove_dependency) {
-      \Drupal::configFactory()->getEditable('search_api.settings')
-        ->set('default_tracker', 'default')
-        ->save();
-    }
+    \Drupal::configFactory()->getEditable('search_api.settings')
+      ->set('default_tracker', 'default')
+      ->save();
 
     // Delete the tracker's dependency.
     $this->dependency->delete();
@@ -375,9 +394,14 @@ class DependencyRemovalTest extends KernelTestBase {
 
     // Depending on whether the plugin should have removed the dependency or
     // not, make sure the right action was taken.
-    $tracker = $this->index->get('tracker');
-    $tracker_config = $this->index->get('tracker_config');
-    if ($remove_dependency) {
+    $tracker_settings = $this->index->get('tracker_settings');
+
+    // Get first tracker in the list if there is a list. There should always
+    // be a tracker so there is no issue in taking the first key.
+    $tracker = array_keys($tracker_settings)[0];
+    $tracker_config = $tracker_settings[$tracker]['settings'];
+
+    if (!$remove_dependency) {
       $this->assertEquals('search_api_test_dependencies', $tracker, 'Tracker not reset');
       $this->assertEmpty($tracker_config, 'Tracker settings adapted');
     }
diff --git a/tests/src/Kernel/LanguageKernelTest.php b/tests/src/Kernel/LanguageKernelTest.php
index 671a957..dacdc3e 100644
--- a/tests/src/Kernel/LanguageKernelTest.php
+++ b/tests/src/Kernel/LanguageKernelTest.php
@@ -104,12 +104,23 @@ class LanguageKernelTest extends KernelTestBase {
     $this->server->save();
 
     // Create a test index.
+    $datasource_id = 'entity:' . $this->testEntityTypeId;
     $this->index = Index::create(array(
       'name' => 'Test Index',
       'id' => 'test_index',
       'status' => 1,
-      'datasources' => array('entity:' . $this->testEntityTypeId),
-      'tracker' => 'default',
+      'datasource_settings' => array(
+        $datasource_id => array(
+          'plugin_id' => $datasource_id,
+          'settings' => array(),
+        ),
+      ),
+      'tracker_settings' => array(
+        'default'=> array(
+          'plugin_id' => 'default',
+          'settings' => array(),
+        ),
+      ),
       'server' => $this->server->id(),
       'options' => array('index_directly' => FALSE),
     ));
@@ -153,10 +164,10 @@ class LanguageKernelTest extends KernelTestBase {
     $this->assertEquals($expected, $datasource_item_ids, 'Datasource returns correct item ids.');
 
     // Test indexing the new entity.
-    $this->assertEquals(0, $this->index->getTracker()->getIndexedItemsCount(), 'The index is empty.');
-    $this->assertEquals(2, $this->index->getTracker()->getTotalItemsCount(), 'There are two items to be indexed.');
+    $this->assertEquals(0, $this->index->getTrackerInstance()->getIndexedItemsCount(), 'The index is empty.');
+    $this->assertEquals(2, $this->index->getTrackerInstance()->getTotalItemsCount(), 'There are two items to be indexed.');
     $this->index->indexItems();
-    $this->assertEquals(2, $this->index->getTracker()->getIndexedItemsCount(), 'Two items have been indexed.');
+    $this->assertEquals(2, $this->index->getTrackerInstance()->getIndexedItemsCount(), 'Two items have been indexed.');
 
     // Now, make the first entity language-specific by assigning a language.
     $default_langcode = $this->langcodes[0];
@@ -175,8 +186,8 @@ class LanguageKernelTest extends KernelTestBase {
     $this->assertEquals($expected, $datasource_item_ids, 'Datasource returns correct item ids.');
 
     // Test that the index needs to be updated.
-    $this->assertEquals(1, $this->index->getTracker()->getIndexedItemsCount(), 'The updated item needs to be reindexed.');
-    $this->assertEquals(2, $this->index->getTracker()->getTotalItemsCount(), 'There are two items in total.');
+    $this->assertEquals(1, $this->index->getTrackerInstance()->getIndexedItemsCount(), 'The updated item needs to be reindexed.');
+    $this->assertEquals(2, $this->index->getTrackerInstance()->getTotalItemsCount(), 'There are two items in total.');
 
     // Set two translations for the first entity and test that the datasource
     // returns three separate item IDs, one for each translation.
@@ -197,8 +208,8 @@ class LanguageKernelTest extends KernelTestBase {
     $this->assertEquals($expected, $datasource_item_ids, 'Datasource returns correct item ids for a translated entity.');
 
     // Test that the index needs to be updated.
-    $this->assertEquals(1, $this->index->getTracker()->getIndexedItemsCount(), 'The updated items needs to be reindexed.');
-    $this->assertEquals(4, $this->index->getTracker()->getTotalItemsCount(), 'There are four items in total.');
+    $this->assertEquals(1, $this->index->getTrackerInstance()->getIndexedItemsCount(), 'The updated items needs to be reindexed.');
+    $this->assertEquals(4, $this->index->getTrackerInstance()->getTotalItemsCount(), 'There are four items in total.');
 
     // Delete one translation and test that the datasource returns only three
     // items.
@@ -215,10 +226,10 @@ class LanguageKernelTest extends KernelTestBase {
     $this->assertEquals($expected, $datasource_item_ids, 'Datasource returns correct item ids for a translated entity.');
 
     // Test reindexing.
-    $this->assertEquals(3, $this->index->getTracker()->getTotalItemsCount(), 'There are three items in total.');
-    $this->assertEquals(1, $this->index->getTracker()->getIndexedItemsCount(), 'The updated items needs to be reindexed.');
+    $this->assertEquals(3, $this->index->getTrackerInstance()->getTotalItemsCount(), 'There are three items in total.');
+    $this->assertEquals(1, $this->index->getTrackerInstance()->getIndexedItemsCount(), 'The updated items needs to be reindexed.');
     $this->index->indexItems();
-    $this->assertEquals(3, $this->index->getTracker()->getIndexedItemsCount(), 'Three items are indexed.');
+    $this->assertEquals(3, $this->index->getTrackerInstance()->getIndexedItemsCount(), 'Three items are indexed.');
   }
 
 }
