diff --git a/libretro-common/file/config_file.c b/libretro-common/file/config_file.c
index 0a63e7781a..7dd671b662 100644
--- a/libretro-common/file/config_file.c
+++ b/libretro-common/file/config_file.c
@@ -66,7 +66,7 @@ struct config_include_list
 };
 
 static config_file_t *config_file_new_internal(
-      const char *path, unsigned depth);
+      const char *path, unsigned depth, config_file_cb_t *cb);
 
 static int config_sort_compare_func(struct config_entry_list *a,
       struct config_entry_list *b)
@@ -267,7 +267,7 @@ static void add_child_list(config_file_t *parent, config_file_t *child)
       parent->tail = NULL;
 }
 
-static void add_sub_conf(config_file_t *conf, char *path)
+static void add_sub_conf(config_file_t *conf, char *path, config_file_cb_t *cb)
 {
    char real_path[PATH_MAX_LENGTH];
    config_file_t         *sub_conf  = NULL;
@@ -314,7 +314,7 @@ static void add_sub_conf(config_file_t *conf, char *path)
 #endif
 
    sub_conf = (config_file_t*)
-      config_file_new_internal(real_path, conf->include_depth + 1);
+      config_file_new_internal(real_path, conf->include_depth + 1, cb);
    if (!sub_conf)
       return;
 
@@ -324,7 +324,7 @@ static void add_sub_conf(config_file_t *conf, char *path)
 }
 
 static bool parse_line(config_file_t *conf,
-      struct config_entry_list *list, char *line)
+      struct config_entry_list *list, char *line, config_file_cb_t *cb)
 {
    char *comment   = NULL;
    char *key_tmp   = NULL;
@@ -351,7 +351,7 @@ static bool parse_line(config_file_t *conf,
             if (conf->include_depth >= MAX_INCLUDE_DEPTH)
                fprintf(stderr, "!!! #include depth exceeded for config. Might be a cycle.\n");
             else
-               add_sub_conf(conf, path);
+               add_sub_conf(conf, path, cb);
             free(path);
          }
          goto error;
@@ -396,18 +396,19 @@ error:
 }
 
 static config_file_t *config_file_new_internal(
-      const char *path, unsigned depth)
+      const char *path, unsigned depth, config_file_cb_t *cb)
 {
    RFILE              *file = NULL;
    struct config_file *conf = (struct config_file*)malloc(sizeof(*conf));
    if (!conf)
       return NULL;
 
-   conf->path          = NULL;
-   conf->entries       = NULL;
-   conf->tail          = NULL;
-   conf->includes      = NULL;
-   conf->include_depth = 0;
+   conf->path                     = NULL;
+   conf->entries                  = NULL;
+   conf->tail                     = NULL;
+   conf->includes                 = NULL;
+   conf->include_depth            = 0;
+   conf->guaranteed_no_duplicates = false ;
 
    if (!path || !*path)
       return conf;
@@ -455,7 +456,7 @@ static config_file_t *config_file_new_internal(
          continue;
       }
 
-      if (*line && parse_line(conf, list, line))
+      if (*line && parse_line(conf, list, line, cb))
       {
          if (conf->entries)
             conf->tail->next = list;
@@ -463,6 +464,9 @@ static config_file_t *config_file_new_internal(
             conf->entries = list;
 
          conf->tail = list;
+
+         if (cb != NULL && list->key != NULL && list->value != NULL)
+            cb->config_file_new_entry_cb(list->key, list->value) ;
       }
 
       free(line);
@@ -551,11 +555,12 @@ config_file_t *config_file_new_from_string(const char *from_string)
    if (!from_string)
       return conf;
 
-   conf->path          = NULL;
-   conf->entries       = NULL;
-   conf->tail          = NULL;
-   conf->includes      = NULL;
-   conf->include_depth = 0;
+   conf->path                     = NULL;
+   conf->entries                  = NULL;
+   conf->tail                     = NULL;
+   conf->includes                 = NULL;
+   conf->include_depth            = 0;
+   conf->guaranteed_no_duplicates = false ;
 
    lines = string_split(from_string, "\n");
    if (!lines)
@@ -580,7 +585,7 @@ config_file_t *config_file_new_from_string(const char *from_string)
 
       if (line && conf)
       {
-         if (*line && parse_line(conf, list, line))
+         if (*line && parse_line(conf, list, line, NULL))
          {
             if (conf->entries)
                conf->tail->next = list;
@@ -600,9 +605,13 @@ config_file_t *config_file_new_from_string(const char *from_string)
    return conf;
 }
 
+config_file_t *config_file_new_with_callback(const char *path, config_file_cb_t *cb)
+{
+   return config_file_new_internal(path, 0, cb);
+}
 config_file_t *config_file_new(const char *path)
 {
-   return config_file_new_internal(path, 0);
+   return config_file_new_internal(path, 0, NULL);
 }
 
 static struct config_entry_list *config_get_entry(const config_file_t *conf,
@@ -834,7 +843,7 @@ bool config_get_bool(config_file_t *conf, const char *key, bool *in)
 void config_set_string(config_file_t *conf, const char *key, const char *val)
 {
    struct config_entry_list *last  = conf->entries;
-   struct config_entry_list *entry = config_get_entry(conf, key, &last);
+   struct config_entry_list *entry = conf->guaranteed_no_duplicates?NULL:config_get_entry(conf, key, &last);
 
    if (entry && !entry->readonly)
    {
diff --git a/libretro-common/include/file/config_file.h b/libretro-common/include/file/config_file.h
index 97fca031a3..e55430472d 100644
--- a/libretro-common/include/file/config_file.h
+++ b/libretro-common/include/file/config_file.h
@@ -58,6 +58,7 @@ struct config_file
    struct config_entry_list *entries;
    struct config_entry_list *tail;
    unsigned include_depth;
+   bool guaranteed_no_duplicates;
 
    struct config_include_list *includes;
 };
@@ -65,6 +66,13 @@ struct config_file
 
 typedef struct config_file config_file_t;
 
+struct config_file_cb
+{
+   void (*config_file_new_entry_cb)(char*, char*);
+};
+
+typedef struct config_file_cb config_file_cb_t ;
+
 /* Config file format
  * - # are treated as comments. Rest of the line is ignored.
  * - Format is: key = value. There can be as many spaces as you like in-between.
@@ -79,6 +87,11 @@ typedef struct config_file config_file_t;
  * NULL path will create an empty config file. */
 config_file_t *config_file_new(const char *path);
 
+/* Loads a config file. Returns NULL if file doesn't exist.
+ * NULL path will create an empty config file.
+ * Includes cb callbacks to run custom code during config file processing.*/
+config_file_t *config_file_new_with_callback(const char *path, config_file_cb_t *cb);
+
 /* Load a config file from a string. */
 config_file_t *config_file_new_from_string(const char *from_string);
 
diff --git a/managers/cheat_manager.c b/managers/cheat_manager.c
index 73971f69d2..d6cc891414 100644
--- a/managers/cheat_manager.c
+++ b/managers/cheat_manager.c
@@ -17,6 +17,7 @@
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
+#include <errno.h>
 
 #include <file/config_file.h>
 #include <file/file_path.h>
@@ -171,6 +172,8 @@ bool cheat_manager_save(const char *path, const char *cheat_database, bool overw
    if (!conf)
       return false;
 
+   conf->guaranteed_no_duplicates = true ;
+
    config_set_int(conf, "cheats", cheat_manager_state.size);
 
    for (i = 0; i < cheat_manager_state.size; i++)
@@ -303,39 +306,118 @@ static void cheat_manager_new(unsigned size)
    return ;
 }
 
+void cheat_manager_load_cb_first_pass(char *key, char *value)
+{
+   errno = 0 ;
+
+   if (string_is_equal(key, "cheats"))
+   {
+      cheat_manager_state.loading_cheat_size = (unsigned)strtoul(value, NULL, 0);
+
+      if (errno != 0)
+         cheat_manager_state.loading_cheat_size = 0 ;
+   }
+}
+
+void cheat_manager_load_cb_second_pass(char *key, char *value)
+{
+   char cheat_num_str[20] ;
+   unsigned cheat_num ;
+   unsigned cheat_idx ;
+   int idx = 0 ;
+   int key_length ;
+   errno = 0 ;
+
+   if (strncmp(key, "cheat", 5) != 0)
+      return ;
+
+   idx = 5 ;
+   key_length = strlen(key) ;
+
+   while (idx < key_length &&  key[idx] >= '0' && key[idx] <= '9' && idx < 24)
+   {
+      cheat_num_str[idx-5] = key[idx] ;
+      idx++ ;
+   }
+
+   cheat_num_str[idx-5] = '\0' ;
+
+   cheat_num = (unsigned)strtoul(cheat_num_str, NULL, 0); ;
+
+   if (cheat_num+cheat_manager_state.loading_cheat_offset >= cheat_manager_state.size)
+      return ;
+
+   key = key+idx+1 ;
+
+   cheat_idx = cheat_num+cheat_manager_state.loading_cheat_offset ;
+
+   if (string_is_equal(key, "address"))
+      cheat_manager_state.cheats[cheat_idx].address = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "address_bit_position"))
+      cheat_manager_state.cheats[cheat_idx].address_mask = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "big_endian"))
+      cheat_manager_state.cheats[cheat_idx].big_endian = (string_is_equal(value,"true") || string_is_equal(value,"1"));
+   else if (string_is_equal(key, "cheat_type"))
+      cheat_manager_state.cheats[cheat_idx].cheat_type = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "code"))
+      cheat_manager_state.cheats[cheat_idx].code = strdup(value) ;
+   else if (string_is_equal(key, "desc"))
+      cheat_manager_state.cheats[cheat_idx].desc = strdup(value) ;
+   else if (string_is_equal(key, "enable"))
+      cheat_manager_state.cheats[cheat_idx].state = (string_is_equal(value,"true") || string_is_equal(value,"1"));
+   else if (string_is_equal(key, "handler"))
+      cheat_manager_state.cheats[cheat_idx].handler = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "memory_search_size"))
+      cheat_manager_state.cheats[cheat_idx].memory_search_size = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "repeat_add_to_address"))
+      cheat_manager_state.cheats[cheat_idx].repeat_add_to_address = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "repeat_add_to_value"))
+      cheat_manager_state.cheats[cheat_idx].repeat_add_to_value = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "repeat_count"))
+      cheat_manager_state.cheats[cheat_idx].repeat_count = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "rumble_port"))
+      cheat_manager_state.cheats[cheat_idx].rumble_port = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "rumble_primary_duration"))
+      cheat_manager_state.cheats[cheat_idx].rumble_primary_duration = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "rumble_primary_strength"))
+      cheat_manager_state.cheats[cheat_idx].rumble_primary_strength = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "rumble_secondary_duration"))
+      cheat_manager_state.cheats[cheat_idx].rumble_secondary_duration = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "rumble_secondary_strength"))
+      cheat_manager_state.cheats[cheat_idx].rumble_secondary_strength = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "rumble_type"))
+      cheat_manager_state.cheats[cheat_idx].rumble_type = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "rumble_value"))
+      cheat_manager_state.cheats[cheat_idx].rumble_value = (unsigned)strtoul(value, NULL, 0);
+   else if (string_is_equal(key, "value"))
+      cheat_manager_state.cheats[cheat_idx].value = (unsigned)strtoul(value, NULL, 0);
+
+}
+
 bool cheat_manager_load(const char *path, bool append)
 {
    unsigned cheats = 0, i;
-   config_file_t *conf    = config_file_new(path);
+   config_file_cb_t cb ;
+   cb.config_file_new_entry_cb = cheat_manager_load_cb_first_pass ;
+   config_file_t *conf    = NULL ;
    unsigned orig_size ;
-   unsigned int* data_ptrs[16] = { NULL};
-   char* keys[16] = {
-         "cheat%u_handler",
-         "cheat%u_memory_search_size",
-         "cheat%u_cheat_type",
-         "cheat%u_value",
-         "cheat%u_address",
-         "cheat%u_address_bit_position",
-         "cheat%u_rumble_type",
-         "cheat%u_rumble_value",
-         "cheat%u_rumble_port",
-         "cheat%u_rumble_primary_strength",
-         "cheat%u_rumble_primary_duration",
-         "cheat%u_rumble_secondary_strength",
-         "cheat%u_rumble_secondary_duration",
-         "cheat%u_repeat_count",
-         "cheat%u_repeat_add_to_value",
-         "cheat%u_repeat_add_to_address",
-   };
+
+   cheat_manager_state.loading_cheat_size = 0 ;
+
+   conf = config_file_new_with_callback(path, &cb);
 
    if (!conf)
       return false;
 
-   config_get_uint(conf, "cheats", &cheats);
+   cheats = cheat_manager_state.loading_cheat_size  ;
 
    if (cheats == 0)
       goto error;
 
+   config_file_free(conf) ;
+   conf = NULL ;
+
+
    cheat_manager_alloc_if_empty() ;
 
    if ( append )
@@ -359,75 +441,25 @@ bool cheat_manager_load(const char *path, bool append)
       cheat_manager_new(cheats);
    }
 
+
    for (i = orig_size; i < cheats; i++)
    {
-      unsigned j;
-      char desc_key[256];
-      char code_key[256];
-      char enable_key[256];
-      char endian_key[256];
-      char *tmp            = NULL;
-      bool tmp_bool        = false;
-
-      data_ptrs[0] = &cheat_manager_state.cheats[i].handler;
-      data_ptrs[1] = &cheat_manager_state.cheats[i].memory_search_size;
-      data_ptrs[2] = &cheat_manager_state.cheats[i].cheat_type;
-      data_ptrs[3] = &cheat_manager_state.cheats[i].value;
-      data_ptrs[4] = &cheat_manager_state.cheats[i].address;
-      data_ptrs[5] = &cheat_manager_state.cheats[i].address_mask;
-      data_ptrs[6] = &cheat_manager_state.cheats[i].rumble_type;
-      data_ptrs[7] = &cheat_manager_state.cheats[i].rumble_value;
-      data_ptrs[8] = &cheat_manager_state.cheats[i].rumble_port;
-      data_ptrs[9] = &cheat_manager_state.cheats[i].rumble_primary_strength;
-      data_ptrs[10] = &cheat_manager_state.cheats[i].rumble_primary_duration;
-      data_ptrs[11] = &cheat_manager_state.cheats[i].rumble_secondary_strength;
-      data_ptrs[12] = &cheat_manager_state.cheats[i].rumble_secondary_duration;
-      data_ptrs[13] = &cheat_manager_state.cheats[i].repeat_count;
-      data_ptrs[14] = &cheat_manager_state.cheats[i].repeat_add_to_value;
-      data_ptrs[15] = &cheat_manager_state.cheats[i].repeat_add_to_address;
-
-      endian_key[0] = desc_key[0] = code_key[0] = enable_key[0] = '\0';
-
-      snprintf(desc_key,   sizeof(desc_key),   "cheat%u_desc",   i-orig_size);
-      snprintf(code_key,   sizeof(code_key),   "cheat%u_code",   i-orig_size);
-      snprintf(enable_key, sizeof(enable_key), "cheat%u_enable", i-orig_size);
-      snprintf(endian_key, sizeof(endian_key), "cheat%u_endian", i-orig_size);
-
       cheat_manager_state.cheats[i].idx = i ;
-
       cheat_manager_state.cheats[i].desc = NULL ;
       cheat_manager_state.cheats[i].code = NULL ;
       cheat_manager_state.cheats[i].state = false ;
       cheat_manager_state.cheats[i].big_endian = false ;
-
-      if (config_get_string(conf, desc_key, &tmp) && !string_is_empty(tmp))
-         cheat_manager_state.cheats[i].desc = strdup(tmp) ;
-
-      if (config_get_string(conf, code_key, &tmp) && !string_is_empty(tmp))
-         cheat_manager_state.cheats[i].code = strdup(tmp) ;
-
-      if (config_get_bool(conf, enable_key, &tmp_bool))
-         cheat_manager_state.cheats[i].state  = tmp_bool;
-
-      if (config_get_bool(conf, endian_key, &tmp_bool))
-         cheat_manager_state.cheats[i].big_endian = tmp_bool;
-
-      if (tmp)
-         free(tmp);
-
       cheat_manager_state.cheats[i].cheat_type = CHEAT_TYPE_SET_TO_VALUE ;
       cheat_manager_state.cheats[i].memory_search_size = 3;
-      for (j = 0 ; j < 16 ; j++ )
-	  {
-         char key[50] ;
-         unsigned val = 0;
-         snprintf(key,   sizeof(key),   keys[j],   i-orig_size);
-
-         if ( config_get_uint(conf, key, &val))
-            *(data_ptrs[j]) = val ;
-      }
    }
 
+   cheat_manager_state.loading_cheat_offset = orig_size ;
+   cb.config_file_new_entry_cb = cheat_manager_load_cb_second_pass ;
+   conf = config_file_new_with_callback(path, &cb);
+
+   if (!conf)
+      return false;
+
    config_file_free(conf);
 
    return true;
diff --git a/managers/cheat_manager.h b/managers/cheat_manager.h
index 917ea711b8..1e0737bcbc 100644
--- a/managers/cheat_manager.h
+++ b/managers/cheat_manager.h
@@ -77,7 +77,8 @@ enum cheat_rumble_type
    RUMBLE_TYPE_LT_VALUE,
    RUMBLE_TYPE_GT_VALUE,
    RUMBLE_TYPE_INCREASE_BY_VALUE,
-   RUMBLE_TYPE_DECREASE_BY_VALUE
+   RUMBLE_TYPE_DECREASE_BY_VALUE,
+   RUMBLE_TYPE_END_LIST
 };
 
 /* Some codes are ridiculously large - over 10000 bytes */
@@ -178,6 +179,8 @@ struct cheat_manager
    unsigned browse_address;
    char working_desc[CHEAT_DESC_SCRATCH_SIZE] ;
    char working_code[CHEAT_CODE_SCRATCH_SIZE] ;
+   unsigned int loading_cheat_size;
+   unsigned int loading_cheat_offset;
 };
 
 typedef struct cheat_manager cheat_manager_t;
diff --git a/menu/menu_driver.h b/menu/menu_driver.h
index a48402c62b..d103367302 100644
--- a/menu/menu_driver.h
+++ b/menu/menu_driver.h
@@ -45,7 +45,7 @@ RETRO_BEGIN_DECLS
 #endif
 
 #ifndef MAX_CHEAT_COUNTERS
-#define MAX_CHEAT_COUNTERS 100
+#define MAX_CHEAT_COUNTERS 6000
 #endif
 
 #define MENU_SETTINGS_CORE_INFO_NONE             0xffff
diff --git a/menu/menu_setting.c b/menu/menu_setting.c
index 1a4d06d20f..7c5dff5bf6 100644
--- a/menu/menu_setting.c
+++ b/menu/menu_setting.c
@@ -4670,7 +4670,7 @@ static bool setting_append_list(
             config_uint_cbs(cheat_manager_state.working_cheat.rumble_type, CHEAT_RUMBLE_TYPE,
                   setting_uint_action_left_default,setting_uint_action_right_default,
                   MENU_ENUM_LABEL_RUMBLE_TYPE_DISABLED,&setting_get_string_representation_uint_as_enum,
-                  RUMBLE_TYPE_DISABLED,RUMBLE_TYPE_GT_VALUE,1) ;
+                  RUMBLE_TYPE_DISABLED,RUMBLE_TYPE_END_LIST-1,1) ;
             (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
 
             config_uint_cbs(cheat_manager_state.working_cheat.rumble_value, CHEAT_RUMBLE_VALUE,