diff --git a/src/box/alter.cc b/src/box/alter.cc
index d1d5002f5b7900379ac4cb7c80d44b372de8faf7..6187135588e0dae9f8fa2cecb9d76bd89af7c104 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -105,74 +105,66 @@ access_check_ddl(uint32_t owner_uid)
 	}
 }
 
+const char *
+map_field_get(const char *map, const char *needle, int needle_type,
+	      int map_field_no)
+{
+	if (map == NULL || mp_typeof(*map) != MP_MAP) {
+		tnt_raise(ClientError, ER_FIELD_TYPE,
+			  map_field_no + INDEX_OFFSET, "map");
+	}
+	uint32_t map_size = mp_decode_map(&map);
+	for (uint32_t i = 0; i < map_size; i++) {
+		const char *key;
+		uint32_t len;
+		if (mp_typeof(*map) != MP_STR) {
+			tnt_raise(ClientError, ER_FIELD_TYPE,
+				  map_field_no + INDEX_OFFSET,
+				  "map key type");
+		}
+		key = mp_decode_str(&map, &len);
+		if (len != strlen(needle) ||
+		    strncasecmp(key, needle, len) != 0) {
+
+			mp_next(&map);
+			continue;
+		}
+		if (mp_typeof(*map) != needle_type) {
+			tnt_raise(ClientError, ER_FIELD_TYPE,
+				  map_field_no + INDEX_OFFSET,
+				  "map value type");
+		}
+		return map;
+	}
+	return NULL;
+}
 
 /** Fill key_opts structure from opts field in tuple of space _index */
 void
-key_opts_create_from_field(struct key_opts *opts, const char *field)
+key_opts_create_from_field(struct key_opts *opts, const char *map)
 {
-	key_opts_create(opts);
-	if (field == NULL)
+	*opts = key_opts_default;
+	if (map == NULL)
 		return;
-	if (mp_typeof(*field) != MP_MAP) {
-		tnt_raise(ClientError, ER_FIELD_TYPE, INDEX_OPTS + INDEX_OFFSET,
-			  "map");
-	}
-	uint32_t map_size = mp_decode_map(&field);
-	for (uint32_t i = 0; i < map_size; i++) {
-		const char *key;
+	const char *field;
+
+	if ((field = map_field_get(map, "unique", MP_BOOL, INDEX_OPTS)))
+		opts->is_unique = mp_decode_bool(&field);
+	if ((field = map_field_get(map, "dimension", MP_UINT, INDEX_OPTS)))
+		opts->dimension = mp_decode_uint(&field);
+	if ((field = map_field_get(map, "distance", MP_STR, INDEX_OPTS))) {
 		uint32_t len;
-		if (mp_typeof(*field) != MP_STR) {
+		const char *distance = mp_decode_str(&field, &len);
+		distance = tuple_field_to_cstr(distance, len);
+
+		enum rtree_index_distance_type distance_type =
+			STR2ENUM(rtree_index_distance_type, distance);
+		if (distance_type == rtree_index_distance_type_MAX) {
 			tnt_raise(ClientError,
-				  ER_FIELD_TYPE, INDEX_OPTS + INDEX_OFFSET,
-				  "string");
-		}
-		key = mp_decode_str(&field, &len);
-		if (len == strlen("unique") &&
-		    memcmp(key, "unique", len) == 0) {
-			if (mp_typeof(*field) != MP_BOOL) {
-				tnt_raise(ClientError,
-					  ER_FIELD_TYPE,
-					  INDEX_OPTS + INDEX_OFFSET,
-					  "bool");
-			}
-			opts->is_unique = mp_decode_bool(&field);
-		} else if (len == strlen("dimension") &&
-			   memcmp(key, "dimension", len) == 0) {
-			if (mp_typeof(*field) != MP_UINT) {
-				tnt_raise(ClientError,
-					  ER_FIELD_TYPE,
-					  INDEX_OPTS + INDEX_OFFSET,
-					  "unsigned");
-			}
-			opts->dimension = mp_decode_uint(&field);
-		} else if (len == strlen("distance") &&
-			   memcmp(key, "distance", len) == 0) {
-			if (mp_typeof(*field) != MP_STR) {
-				tnt_raise(ClientError,
-					  ER_FIELD_TYPE,
-					  INDEX_OPTS + INDEX_OFFSET,
-					  "unsigned");
-			}
-			const char *str_distance;
-			uint32_t distance_len;
-			str_distance = mp_decode_str(&field, &distance_len);
-			if (distance_len == strlen("euclid") &&
-				memcmp(str_distance, "euclid",
-				       distance_len) == 0) {
-				opts->distance = EUCLID;
-			} else if (distance_len == strlen("manhattan") &&
-				   memcmp(str_distance, "manhattan",
-					  distance_len) == 0) {
-				opts->distance = MANHATTAN;
-			} else {
-				tnt_raise(ClientError,
-					  ER_FIELD_TYPE,
-					  INDEX_OPTS + INDEX_OFFSET,
-					  "string euclid/manhattan");
-			}
-		} else {
-			mp_next(&field);
+				  ER_UNKNOWN_RTREE_INDEX_DISTANCE_TYPE,
+				  distance);
 		}
+		opts->distance = distance_type;
 	}
 }
 
@@ -208,10 +200,16 @@ key_def_new_from_tuple(struct tuple *tuple)
 		part_count = mp_decode_array(&parts);
 	} else {
 		/* 1.6.5 _index space structure */
-		key_opts_create(&opts);
+		opts = key_opts_default;
 		opts.is_unique = tuple_field_u32(tuple, INDEX_165_IS_UNIQUE);
 		part_count = tuple_field_u32(tuple, INDEX_165_PART_COUNT);
 	}
+	/**
+	 * XXX this is an ugly clutch in absence of Lua-level
+	 * index-type specific defaults.
+	 */
+	if (opts.dimension == 0 && type == RTREE)
+		opts.dimension = 2;
 	key_def = key_def_new(id, index_id, name, type, &opts, part_count);
 	auto scoped_guard = make_scoped_guard([=] { key_def_delete(key_def); });
 
diff --git a/src/box/errcode.h b/src/box/errcode.h
index 13a776a7242f59cba8fcc84c4f939ec0f5041597..57008e1b1f1405ed50fac53c4c0732f0d91b762d 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -156,6 +156,7 @@ struct errcode_record {
 	/*100 */_(ER_FUNCTION_LANGUAGE,		2, "Unsupported language '%s' specified for function '%s'") \
 	/*101 */_(ER_RTREE_RECT,		2, "RTree: %s must be an array with %u (point) or %u (rectangle/box) numeric coordinates") \
 	/*102 */_(ER_PROC_C,			2, "%s") \
+	/*103 */_(ER_UNKNOWN_RTREE_INDEX_DISTANCE_TYPE,	2, "Unknown RTREE index distance type %s") \
 
 /*
  * !IMPORTANT! Please follow instructions at start of the file
diff --git a/src/box/key_def.cc b/src/box/key_def.cc
index 1b42d5ceb0492d83a8ae70080f6b2f9ff6f1621b..c898674434005151c77de2c412ee3f642c544352 100644
--- a/src/box/key_def.cc
+++ b/src/box/key_def.cc
@@ -36,7 +36,8 @@
 
 const char *field_type_strs[] = {"UNKNOWN", "NUM", "STR", "ARRAY", "NUMBER", ""};
 STRS(index_type, ENUM_INDEX_TYPE);
-STRS(distance_type, ENUM_DISTANCE_TYPE);
+
+const char *rtree_index_distance_type_strs[] = { "EUCLID", "MANHATTAN" };
 
 const char *func_language_strs[] = {"LUA", "C"};
 
@@ -48,6 +49,10 @@ const uint32_t key_mp_type[] = {
 	/* [NUMBER]  =  */  (1U << MP_UINT) | (1U << MP_INT) | (1U << MP_FLOAT) | (1U << MP_DOUBLE),
 };
 
+const struct key_opts key_opts_default = {
+	true, 0, RTREE_INDEX_DISTANCE_TYPE_EUCLID
+};
+
 enum schema_object_type
 schema_object_type(const char *name)
 {
diff --git a/src/box/key_def.h b/src/box/key_def.h
index 9c76a48c0abc60f85d4dc16d23737a319dbf62a9..c9e6e74976b4dcec197c9ac8420a44d7ddc83910 100644
--- a/src/box/key_def.h
+++ b/src/box/key_def.h
@@ -99,12 +99,14 @@ field_type_maxlen(enum field_type type)
 ENUM(index_type, ENUM_INDEX_TYPE);
 extern const char *index_type_strs[];
 
-#define ENUM_DISTANCE_TYPE(_) \
-	_(EUCLID,    0) /* Euclid distance, sqrt(dx*dx + dy*dy) */   \
-	_(MANHATTAN, 1) /* Manhattan distance, fabs(dx) + fabs(dy) */   \
-
-ENUM(distance_type, ENUM_DISTANCE_TYPE);
-extern const char *distance_type_strs[];
+enum rtree_index_distance_type {
+	 /* Euclid distance, sqrt(dx*dx + dy*dy) */
+	RTREE_INDEX_DISTANCE_TYPE_EUCLID,
+	/* Manhattan distance, fabs(dx) + fabs(dy) */
+	RTREE_INDEX_DISTANCE_TYPE_MANHATTAN,
+	rtree_index_distance_type_MAX
+};
+extern const char *rtree_index_distance_type_strs[];
 
 /** Descriptor of a single part in a multipart key. */
 struct key_part {
@@ -126,16 +128,10 @@ struct key_opts {
 	/**
 	 * RTREE distance type.
 	 */
-	distance_type distance;
+	enum rtree_index_distance_type distance;
 };
 
-static inline void
-key_opts_create(struct key_opts *opts)
-{
-	opts->is_unique = true;
-	opts->dimension = 2;
-	opts->distance = EUCLID;
-}
+extern const struct key_opts key_opts_default;
 
 static inline int
 key_opts_cmp(const struct key_opts *o1, const struct key_opts *o2)
diff --git a/src/box/memtx_rtree.cc b/src/box/memtx_rtree.cc
index 1cdda13d9fd827889579eb716ab3c5c49f6cd288..6c773d89e61b90c09aa7c2170c02aa519ef81282 100644
--- a/src/box/memtx_rtree.cc
+++ b/src/box/memtx_rtree.cc
@@ -163,8 +163,8 @@ MemtxRTree::MemtxRTree(struct key_def *key_def)
 	}
 
 	memtx_index_arena_init();
-	assert((int)RTREE_EUCLID == (int)EUCLID);
-	assert((int)RTREE_MANHATTAN == (int)MANHATTAN);
+	assert((int)RTREE_EUCLID == (int)RTREE_INDEX_DISTANCE_TYPE_EUCLID);
+	assert((int)RTREE_MANHATTAN == (int)RTREE_INDEX_DISTANCE_TYPE_MANHATTAN);
 	enum rtree_distance_type distance_type =
 		(enum rtree_distance_type)(int)key_def->opts.distance;
 	rtree_init(&m_tree, m_dimension, MEMTX_EXTENT_SIZE,
diff --git a/src/box/schema.cc b/src/box/schema.cc
index 0aea928ebe3e3be3711f39fa5ac87a6fb514b7e3..c6133cad13c12c3959acddc1ca636078564aab91 100644
--- a/src/box/schema.cc
+++ b/src/box/schema.cc
@@ -250,9 +250,7 @@ schema_init()
 	struct space_def def = {
 		BOX_SCHEMA_ID, ADMIN, 0, "_schema", "memtx", false
 	};
-	struct key_opts opts = { true /* is_unique */,
-				 0 /* dimension */,
-				 EUCLID /* distance */};
+	struct key_opts opts = key_opts_default;
 	struct key_def *key_def = key_def_new(def.id,
 					      0 /* index id */,
 					      "primary", /* name */
diff --git a/src/box/sophia_engine.cc b/src/box/sophia_engine.cc
index 9a004ded9d907c65f1ec50c424acb69942715928..a70423b6aa351fe5e6da2e43d09ae2c14c30861f 100644
--- a/src/box/sophia_engine.cc
+++ b/src/box/sophia_engine.cc
@@ -320,9 +320,7 @@ sophia_join_key_def(void *env, void *db)
 	uint32_t id = sp_getint(db, "id");
 	uint32_t count = sp_getint(db, "key-count");
 	struct key_def *key_def;
-	struct key_opts key_opts = { true /* is_unique */,
-				     0 /* dimension */,
-				     EUCLID /* distance */ };
+	struct key_opts key_opts = key_opts_default;
 	key_def = key_def_new(id, 0, "sophia_join", TREE, &key_opts, count);
 	int i = 0;
 	while (i < count) {
diff --git a/src/box/tuple.cc b/src/box/tuple.cc
index 25836fde3ca7d2daf4a2bb9743e9df65954b5a8f..6aa2f2df5ec7dfd81ee9141cca9e4fd639636aa2 100644
--- a/src/box/tuple.cc
+++ b/src/box/tuple.cc
@@ -365,11 +365,15 @@ tuple_next(struct tuple_iterator *it)
 extern inline uint32_t
 tuple_next_u32(struct tuple_iterator *it);
 
-static const char *
+const char *
 tuple_field_to_cstr(const char *field, uint32_t len)
 {
-	static __thread char buf[256];
-	len = MIN(len, sizeof(buf) - 1);
+	enum { MAX_STR_BUFS = 3, MAX_BUF_LEN = 256 };
+	static __thread char bufs[MAX_STR_BUFS][MAX_BUF_LEN];
+	static __thread int i = 0;
+	char *buf = bufs[i];
+	i = (i + 1) % MAX_STR_BUFS;
+	len = MIN(len, MAX_BUF_LEN - 1);
 	memcpy(buf, field, len);
 	buf[len] = '\0';
 	return buf;
diff --git a/src/box/tuple.h b/src/box/tuple.h
index 315f6eb410d853d31908cfa9bb678a7b27ce784d..98396201365543f3c9ed78658a66a7c9f6547828 100644
--- a/src/box/tuple.h
+++ b/src/box/tuple.h
@@ -390,6 +390,10 @@ tuple_field_num(const struct tuple* tuple, uint32_t field_no)
 const char *
 tuple_field_cstr(struct tuple *tuple, uint32_t i);
 
+/** Helper method for the above function. */
+const char *
+tuple_field_to_cstr(const char *field, uint32_t len);
+
 /**
  * @brief Tuple Interator
  */
diff --git a/test/box/misc.result b/test/box/misc.result
index 0a4bd84df56668356e4478b72fc3fdfbbecf6c08..03daae50f2ebdc57bdd98d77c9b7104cbb3c87d3 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -250,6 +250,7 @@ t;
   - 'box.error.CREATE_FUNCTION : 50'
   - 'box.error.SOPHIA : 60'
   - 'box.error.NO_SUCH_INDEX : 35'
+  - 'box.error.UNKNOWN_RTREE_INDEX_DISTANCE_TYPE : 103'
   - 'box.error.TUPLE_IS_TOO_LONG : 27'
   - 'box.error.UNKNOWN_SERVER : 62'
   - 'box.error.FUNCTION_EXISTS : 52'