diff --git a/gio/gsettings.c b/gio/gsettings.c
index ad8c408..efad5d8 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -33,6 +33,9 @@
 
 #include "strinfo.c"
 
+#define EXISTS_KEY ".exists"
+#define ANTI_DEFAULT_KEY ".anti-Default"
+
 /**
  * SECTION:gsettings
  * @short_description: High-level API for application settings
@@ -1481,6 +1484,402 @@ g_settings_set_flags (GSettings   *settings,
   return success;
 }
 
+static gboolean
+settings_list_item_is_default_item (const gchar *name)
+{
+  GSettingsSchemaSource *source;
+  GSettingsSchema       *schema;
+  gboolean               result = FALSE;
+
+  source = g_settings_schema_source_get_default ();
+  schema = g_settings_schema_source_lookup (source, name, FALSE);
+
+  if (schema != NULL)
+    {
+      result = TRUE;
+      g_settings_schema_unref (schema);
+    }
+
+  return result;
+}
+
+static GVariant *
+settings_list_get_list (GSettings  *settings,
+                        gchar     **path)
+{
+  GVariant *list;
+  gchar    *_path;
+
+  _path = g_strconcat (g_settings_schema_get_path (settings->priv->schema),
+                       EXISTS_KEY,
+                       NULL);
+  list = g_settings_backend_read (settings->priv->backend,
+                                  _path,
+                                  G_VARIANT_TYPE ("as"),
+                                  FALSE);
+
+  if (path != NULL)
+    *path = _path;
+  else
+    g_free (_path);
+
+  return list;
+}
+
+static gboolean
+settings_list_anti_default_exists (GSettings *settings)
+{
+  GVariant *value;
+  gboolean  exists = FALSE;
+  gchar    *path;
+
+  path = g_strconcat (g_settings_schema_get_path (settings->priv->schema),
+                      ANTI_DEFAULT_KEY,
+                      NULL);
+  value = g_settings_backend_read (settings->priv->backend,
+                                   path,
+                                   G_VARIANT_TYPE ("s"),
+                                   FALSE);
+  g_free (path);
+
+  if (value != NULL)
+    {
+      exists = TRUE;
+      g_variant_unref (value);
+    }
+
+  return exists;
+}
+
+/**
+ * g_settings_list_get_item:
+ * @settings: a #GSettings object
+ * @name: the name of the item to get
+ *
+ * Gets the item that is stored in the gsettings list in @settings.
+ *
+ * Since: 2.46
+ */
+GSettings *
+g_settings_list_get_item (GSettings   *settings,
+                          const gchar *name)
+{
+  GSettings *item = NULL;
+  gchar     *path;
+
+  if (g_settings_schema_get_list_of (settings->priv->schema) == NULL)
+    {
+      g_critical ("g_settings_list_get_item: given schema '%s' is not a list of a schema",
+                  g_settings_schema_get_id (settings->priv->schema));
+
+      return NULL;
+    }
+
+  if (settings_list_item_is_default_item (name))
+    {
+      gboolean item_exists = FALSE;
+
+      if (!settings_list_anti_default_exists (settings))
+        {
+          item_exists = TRUE;
+        }
+      else
+        {
+          const gchar **db_items = NULL;
+          GVariant     *list;
+          gsize         i;
+
+          list = settings_list_get_list (settings, NULL);
+          if (list != NULL)
+            {
+              db_items = g_variant_get_strv (list, NULL);
+              for (i = 0; db_items[i] != NULL; i++)
+                {
+                  if (g_strcmp0 (name, db_items[i]) == 0)
+                    {
+                      item_exists = TRUE;
+                      break;
+                    }
+                }
+
+              g_free (db_items);
+              g_variant_unref (list);
+            }
+        }
+
+      if (item_exists)
+        item = g_settings_new (name);
+    }
+  else
+    {
+      path = g_strconcat (g_settings_schema_get_path (settings->priv->schema),
+                          name, "/", NULL);
+      item = g_settings_new_with_path (g_settings_schema_get_list_of (settings->priv->schema),
+                                       path);
+      g_free (path);
+    }
+
+  return item;
+}
+
+/**
+ * g_settings_list_add_item:
+ * @settings: a #GSettings object
+ *
+ * Adds item to the gsettings list in @settings.
+ *
+ * Returns: (transfer full): a name of the new list item
+ *
+ * Since: 2.46
+ */
+gchar *
+g_settings_list_add_item (GSettings *settings)
+{
+  GVariantBuilder   array_builder;
+  GVariant         *list;
+  gint64            time;
+  gchar           **item_list = NULL;
+  gchar            *path = NULL;
+  gchar            *name = NULL;
+  gsize             i;
+
+  if (g_settings_schema_get_list_of (settings->priv->schema) == NULL)
+    {
+      g_critical ("g_settings_list_add_item: given schema '%s' is not a list of a schema",
+                  g_settings_schema_get_id (settings->priv->schema));
+
+      return NULL;
+    }
+
+  list = settings_list_get_list (settings, &path);
+  if (path != NULL)
+    {
+      /* TODO: Improve generation of the name */
+      time = g_get_monotonic_time ();
+      name = g_strdup_printf ("%ld", time);
+
+      /* Construct new item list which contains a new item. */
+      g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
+      if (list != NULL)
+        {
+          item_list = g_variant_dup_strv (list, NULL);
+          if (item_list != NULL)
+            {
+              for (i = 0; item_list[i] != NULL; i++)
+                g_variant_builder_add (&array_builder, "s", item_list[i]);
+
+              g_strfreev (item_list);
+            }
+
+          g_variant_unref (list);
+        }
+      g_variant_builder_add (&array_builder, "s", name);
+
+
+      /* Write the new list. */
+      g_settings_backend_write (settings->priv->backend, path,
+                                g_variant_new ("as", &array_builder),
+                                NULL);
+
+      g_free (path);
+    }
+
+  return name;
+}
+
+/**
+ * g_settings_list_add_item:
+ * @settings: a #GSettings object
+ * @name: the name of the item to remove
+ *
+ * Removes item from the gsettings list in @settings.
+ *
+ * Since: 2.46
+ */
+void
+g_settings_list_remove_item (GSettings   *settings,
+                             const gchar *name)
+{
+  GVariantBuilder   array_builder;
+  GVariant         *list;
+  gchar            *path = NULL;
+  gchar            *reset_path = NULL;
+  gsize             count = 0;
+  gsize             i;
+
+  if (g_settings_schema_get_list_of (settings->priv->schema) == NULL)
+    {
+      g_critical ("g_settings_list_remove_item: given schema '%s' is not a list of a schema",
+                  g_settings_schema_get_id (settings->priv->schema));
+
+      return;
+    }
+
+  /* Construct new item list which does not contain the removed item. */
+  g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
+
+  /* Create '.anti-Default' key if the item is a default item and
+     move all remaining default items to the '.exists' list */
+  if (settings_list_item_is_default_item (name) &&
+      !settings_list_anti_default_exists (settings))
+    {
+      gchar **extending_schemas;
+      gchar  *anti_default_path;
+
+      extending_schemas = g_settings_schema_get_extending_schemas (settings->priv->schema);
+      if (extending_schemas != NULL)
+        {
+          for (i = 0; extending_schemas[i] != NULL; i++)
+            {
+              if (g_strcmp0 (extending_schemas[i], name) != 0)
+                {
+                  g_variant_builder_add (&array_builder, "s", extending_schemas[i]);
+                  count++;
+                }
+              else
+                {
+                  GSettingsSchema *schema;
+
+                  schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
+                                                            name, FALSE);
+
+                  if (schema != NULL)
+                    {
+                      reset_path = g_strdup (g_settings_schema_get_path (schema));
+                      g_settings_schema_unref (schema);
+                    }
+                }
+            }
+        }
+
+      g_strfreev (extending_schemas);
+
+      anti_default_path = g_strconcat (g_settings_schema_get_path (settings->priv->schema),
+                                       ANTI_DEFAULT_KEY,
+                                       NULL);
+      g_settings_backend_write (settings->priv->backend, anti_default_path,
+                                g_variant_new_string (""),
+                                NULL);
+      g_free (anti_default_path);
+    }
+
+  list = settings_list_get_list (settings, &path);
+  if (list != NULL)
+    {
+      const gchar **item_list = NULL;
+
+      item_list = g_variant_get_strv (list, NULL);
+      if (item_list != NULL)
+        {
+          for (i = 0; item_list[i] != NULL; i++)
+            {
+              if (g_strcmp0 (item_list[i], name) != 0)
+                {
+                  g_variant_builder_add (&array_builder, "s", item_list[i]);
+                  count++;
+                }
+              else
+                {
+                  reset_path = g_strconcat (g_settings_schema_get_path (settings->priv->schema),
+                                            name, NULL);
+                }
+            }
+
+          g_free (item_list);
+        }
+
+      g_variant_unref (list);
+    }
+
+  /* Reset the removed item of the settings list. */
+  if (reset_path != NULL)
+    {
+      g_settings_backend_reset (settings->priv->backend, reset_path, NULL);
+      g_free (reset_path);
+    }
+
+  /* Write the new list or reset the key holding it if it is empty. */
+  if (path != NULL)
+    {
+      if (count != 0)
+        {
+          g_settings_backend_write (settings->priv->backend, path,
+                                    g_variant_new ("as", &array_builder),
+                                    NULL);
+        }
+      else
+        {
+          g_settings_backend_reset (settings->priv->backend, path, NULL);
+          g_variant_builder_clear (&array_builder);
+        }
+
+      g_free (path);
+    }
+}
+
+/**
+ * g_settings_list_get_items:
+ * @settings: a #GSettings object
+ *
+ * Get list of items in the gsettings list in @settings.
+ *
+ * Returns: (transfer full): a new NULL-terminated array of names of gsettings list items
+ *
+ * Since: 2.46
+ */
+gchar **
+g_settings_list_get_items (GSettings *settings)
+{
+  GVariant  *list;
+  gchar    **db_items = NULL;
+  gchar    **extending_schemas = NULL;
+  gchar    **items;
+  gsize      extending_schemas_count = 0;
+  gsize      db_items_count = 0;
+  gsize      i;
+
+  if (g_settings_schema_get_list_of (settings->priv->schema) == NULL)
+    {
+      g_critical ("g_settings_list_get_items: given schema '%s' is not a list of a schema",
+                  g_settings_schema_get_id (settings->priv->schema));
+
+      return NULL;
+    }
+
+  /* Return only items from '.exists' list if there is '.anti-Default' key */
+  if (!settings_list_anti_default_exists (settings))
+    {
+      extending_schemas = g_settings_schema_get_extending_schemas (settings->priv->schema);
+      if (extending_schemas != NULL)
+        extending_schemas_count = g_strv_length (extending_schemas);
+    }
+
+  list = settings_list_get_list (settings, NULL);
+  if (list != NULL)
+    {
+      db_items = g_variant_dup_strv (list, NULL);
+      db_items_count = g_strv_length (db_items);
+      g_variant_unref (list);
+    }
+
+  if (db_items_count > 0 || extending_schemas_count > 0)
+    {
+      items = g_new0 (gchar *, extending_schemas_count + db_items_count + 1);
+
+      for (i = 0; i < extending_schemas_count; i++)
+        items[i] = extending_schemas[i];
+
+      for (i = 0; i < db_items_count; i++)
+        items[i + extending_schemas_count] = db_items[i];
+    }
+
+  g_free (db_items);
+  g_free (extending_schemas);
+
+  return items;
+}
+
+
 /**
  * g_settings_set_value:
  * @settings: a #GSettings object
diff --git a/gio/gsettings.h b/gio/gsettings.h
index 02a0337..ab33f42 100644
--- a/gio/gsettings.h
+++ b/gio/gsettings.h
@@ -103,6 +103,20 @@ gboolean                g_settings_range_check                          (GSettin
                                                                          GVariant           *value);
 
 GLIB_AVAILABLE_IN_ALL
+gchar *                 g_settings_list_add_item                        (GSettings          *settings);
+
+GLIB_AVAILABLE_IN_ALL
+void                    g_settings_list_remove_item                     (GSettings          *settings,
+                                                                         const gchar        *name);
+
+GLIB_AVAILABLE_IN_ALL
+GSettings *             g_settings_list_get_item                        (GSettings          *settings,
+                                                                         const gchar        *name);
+
+GLIB_AVAILABLE_IN_ALL
+gchar **                g_settings_list_get_items                       (GSettings          *settings);
+
+GLIB_AVAILABLE_IN_ALL
 gboolean                g_settings_set_value                            (GSettings          *settings,
                                                                          const gchar        *key,
                                                                          GVariant           *value);
diff --git a/gio/gsettingsschema-internal.h b/gio/gsettingsschema-internal.h
index c6a905f..69d4d9c 100644
--- a/gio/gsettingsschema-internal.h
+++ b/gio/gsettingsschema-internal.h
@@ -41,7 +41,9 @@ struct _GSettingsSchemaKey
   gint ref_count;
 };
 
+gchar **                g_settings_schema_get_extending_schemas         (GSettingsSchema  *schema);
 const gchar *           g_settings_schema_get_gettext_domain            (GSettingsSchema  *schema);
+const gchar *           g_settings_schema_get_list_of                   (GSettingsSchema  *schema);
 GVariantIter *          g_settings_schema_get_value                     (GSettingsSchema  *schema,
                                                                          const gchar      *key);
 const GQuark *          g_settings_schema_list                          (GSettingsSchema  *schema,
diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c
index e3966fd..0f6eeef 100644
--- a/gio/gsettingsschema.c
+++ b/gio/gsettingsschema.c
@@ -153,6 +153,7 @@ struct _GSettingsSchema
   gchar *id;
 
   GSettingsSchema *extends;
+  GSettingsSchema *list_of;
 
   gint ref_count;
 };
@@ -413,6 +414,7 @@ g_settings_schema_source_lookup (GSettingsSchemaSource *source,
   GSettingsSchema *schema;
   GvdbTable *table;
   const gchar *extends;
+  const gchar *list_of;
 
   g_return_val_if_fail (source != NULL, NULL);
   g_return_val_if_fail (schema_id != NULL, NULL);
@@ -446,6 +448,14 @@ g_settings_schema_source_lookup (GSettingsSchemaSource *source,
         g_warning ("Schema '%s' extends schema '%s' but we could not find it", schema_id, extends);
     }
 
+  list_of = g_settings_schema_get_string (schema, ".list-of");
+  if (list_of)
+    {
+      schema->list_of = g_settings_schema_source_lookup (source, list_of, TRUE);
+      if (schema->list_of == NULL)
+        g_warning ("Schema '%s' is list of schema '%s' but we could not find it", schema_id, list_of);
+    }
+
   return schema;
 }
 
@@ -919,6 +929,9 @@ g_settings_schema_unref (GSettingsSchema *schema)
       if (schema->extends)
         g_settings_schema_unref (schema->extends);
 
+      if (schema->list_of)
+        g_settings_schema_unref (schema->list_of);
+
       g_settings_schema_source_unref (schema->source);
       gvdb_table_unref (schema->table);
       g_free (schema->items);
@@ -997,6 +1010,15 @@ g_settings_schema_get_gettext_domain (GSettingsSchema *schema)
   return schema->gettext_domain;
 }
 
+const gchar *
+g_settings_schema_get_list_of (GSettingsSchema *schema)
+{
+  if (schema->list_of)
+    return g_settings_schema_get_id (schema->list_of);
+  else
+    return NULL;
+}
+
 /**
  * g_settings_schema_has_key:
  * @schema: a #GSettingsSchema
@@ -1056,6 +1078,82 @@ g_settings_schema_list_children (GSettingsSchema *schema)
   return strv;
 }
 
+static gboolean
+g_settings_schema_is_parent_schema (GSettingsSchema *parent_schema,
+                                    GSettingsSchema *child_schema)
+{
+  GSettingsSchema *s;
+
+  g_return_val_if_fail (parent_schema != NULL && child_schema != NULL, FALSE);
+
+  if (child_schema->extends)
+    {
+      for (s = child_schema->extends; s; s = s->extends)
+        {
+          if (g_strcmp0 (g_settings_schema_get_list_of (parent_schema),
+                         g_settings_schema_get_id (s)) == 0)
+            return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+gchar **
+g_settings_schema_get_extending_schemas (GSettingsSchema *schema)
+{
+  GSettingsSchemaSource  *source;
+  GSettingsSchema        *child_schema;
+  GList                  *schemas_list = NULL;
+  GList                  *iter;
+  gchar                 **relocatable = NULL;
+  gchar                 **non_relocatable = NULL;
+  gchar                 **schemas = NULL;
+  gsize                  i;
+
+  source = g_settings_schema_source_get_default ();
+  g_settings_schema_source_list_schemas (source,
+                                         FALSE,
+                                         &non_relocatable,
+                                         &relocatable);
+
+  if (relocatable)
+    {
+      for (i = 0; relocatable[i] != NULL; i++)
+        {
+          child_schema = g_settings_schema_source_lookup (source, relocatable[i], FALSE);
+          if (g_settings_schema_is_parent_schema (schema, child_schema))
+            schemas_list = g_list_append (schemas_list, g_strdup (g_settings_schema_get_id (child_schema)));
+          g_settings_schema_unref (child_schema);
+        }
+
+      g_strfreev (relocatable);
+    }
+
+  if (non_relocatable)
+    {
+      for (i = 0; non_relocatable[i] != NULL; i++)
+        {
+          child_schema = g_settings_schema_source_lookup (source, non_relocatable[i], FALSE);
+          if (g_settings_schema_is_parent_schema (schema, child_schema))
+            schemas_list = g_list_append (schemas_list, g_strdup (g_settings_schema_get_id (child_schema)));
+          g_settings_schema_unref (child_schema);
+        }
+
+      g_strfreev (non_relocatable);
+    }
+
+  if (schemas_list != NULL)
+    {
+      schemas = g_new0 (gchar *, g_list_length (schemas_list) + 1);
+      for (iter = schemas_list, i = 0; iter != NULL; iter = iter->next, i++)
+        schemas[i] = (gchar *) iter->data;
+      g_list_free (schemas_list);
+    }
+
+  return schemas;
+}
+
 const GQuark *
 g_settings_schema_list (GSettingsSchema *schema,
                         gint            *n_items)
