diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt
index f442df2050fc5aa2b3e9929e214fd49af74b8f92..a37523dceaf7190a287ccd3bc967eaf7f281c6b3 100644
--- a/src/box/CMakeLists.txt
+++ b/src/box/CMakeLists.txt
@@ -26,6 +26,7 @@ tarantool_module("box"
     tree_index.cc
     bitset_index.cc
     engine.cc
+    engine_memtx.cc
     space.cc
     alter.cc
     schema.cc
diff --git a/src/box/alter.cc b/src/box/alter.cc
index 9f8b748c990efe21e0216230c9f82188230ce217..67cb1ae033e3633e9f0eab92a4d55b67c8345b64 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -442,7 +442,9 @@ alter_space_do(struct txn *txn, struct alter_space *alter,
 	 * since engine.recover does different things depending on
 	 * the recovery phase.
 	 */
-	alter->new_space->engine = alter->old_space->engine;
+	alter->new_space->engine->recovery =
+		alter->old_space->engine->recovery;
+
 	memcpy(alter->new_space->access, alter->old_space->access,
 	       sizeof(alter->old_space->access));
 	/*
@@ -492,9 +494,12 @@ ModifySpace::prepare(struct alter_space *alter)
 			  (unsigned) space_id(alter->old_space),
 			  "can not change space engine");
 
+	engine_recovery *recovery =
+		&alter->old_space->engine->recovery;
+
 	if (def.arity != 0 &&
 	    def.arity != alter->old_space->def.arity &&
-	    alter->old_space->engine.state != READY_NO_KEYS &&
+	    recovery->state != READY_NO_KEYS &&
 	    space_size(alter->old_space) > 0) {
 
 		tnt_raise(ClientError, ER_ALTER_SPACE,
@@ -502,7 +507,7 @@ ModifySpace::prepare(struct alter_space *alter)
 			  "can not change arity on a non-empty space");
 	}
 	if (def.temporary != alter->old_space->def.temporary &&
-	    alter->old_space->engine.state != READY_NO_KEYS &&
+	    recovery->state != READY_NO_KEYS &&
 	    space_size(alter->old_space) > 0) {
 		tnt_raise(ClientError, ER_ALTER_SPACE,
 			  (unsigned) space_id(alter->old_space),
@@ -576,7 +581,7 @@ DropIndex::alter(struct alter_space *alter)
 	 *   can be put back online properly with
 	 *   engine_no_keys.recover.
 	 */
-	engine_derive(&alter->new_space->engine);
+	alter->new_space->engine->recover_derive();
 }
 
 void
@@ -765,7 +770,10 @@ AddIndex::alter(struct alter_space *alter)
 	 * READY_NO_KEYS is when a space has no functional keys.
 	 * Possible both during and after recovery.
 	 */
-	if (alter->new_space->engine.state == READY_NO_KEYS) {
+	engine_recovery *recovery =
+		&alter->new_space->engine->recovery;
+
+	if (recovery->state == READY_NO_KEYS) {
 		if (new_key_def->iid == 0) {
 			/*
 			 * Adding a primary key: bring the space
@@ -777,7 +785,7 @@ AddIndex::alter(struct alter_space *alter)
 			 * key. After recovery, it means building
 			 * all keys.
 			 */
-			alter->new_space->engine.recover(alter->new_space);
+			recovery->recover(alter->new_space);
 		} else {
 			/*
 			 * Adding a secondary key: nothing to do.
@@ -796,8 +804,9 @@ AddIndex::alter(struct alter_space *alter)
 	}
 	Index *pk = index_find(alter->old_space, 0);
 	Index *new_index = index_find(alter->new_space, new_key_def->iid);
+
 	/* READY_PRIMARY_KEY is a state that only occurs during WAL recovery. */
-	if (alter->new_space->engine.state == READY_PRIMARY_KEY) {
+	if (recovery->state == READY_PRIMARY_KEY) {
 		if (new_key_def->iid == 0) {
 			/*
 			 * Bulk rebuild of the new primary key
diff --git a/src/box/box.cc b/src/box/box.cc
index 2074559d397744cb81e8580fe79a2eb7631cf6d0..d6fbce91a8a9eb6bd22b1ad0dd167894a2b50eee 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -47,6 +47,7 @@ extern "C" {
 #include "lua/call.h"
 #include "schema.h"
 #include "engine.h"
+#include "engine_memtx.h"
 #include "space.h"
 #include "port.h"
 #include "request.h"
@@ -278,6 +279,13 @@ box_free(void)
 	stat_free();
 }
 
+static void
+box_engine_init()
+{
+	MEMTX *memtx = new MEMTX();
+	engine_register(memtx);
+}
+
 void
 box_init()
 {
@@ -287,7 +295,7 @@ box_init()
 	tuple_init(cfg.slab_alloc_arena, cfg.slab_alloc_minimal,
 		   cfg.slab_alloc_factor);
 
-	engine_register(&engine_memtx);
+	box_engine_init();
 
 	schema_init();
 	user_cache_init();
diff --git a/src/box/engine.cc b/src/box/engine.cc
index b389267a21ff1aae15dee69222a21febef9e7b1a..e393cde49598ba703783c9214d88e204194ff8a8 100644
--- a/src/box/engine.cc
+++ b/src/box/engine.cc
@@ -34,19 +34,40 @@
 #include <stdlib.h>
 #include <string.h>
 
-RLIST_HEAD(engines);
+static RLIST_HEAD(engines);
 
-/** Register engine instance. */
-void engine_register(struct engine *engine)
+EngineFactory::EngineFactory(const char *engine_name)
+	:name(engine_name),
+	 link(RLIST_INITIALIZER(link))
+{}
+
+void EngineFactory::init()
+{}
+
+void EngineFactory::shutdown()
+{}
+
+void EngineFactory::close(Engine*)
+{}
+
+Engine::Engine(EngineFactory *f)
+	:host(f)
+{
+	/* derive recovery state from engine factory */
+	recover_derive();
+}
+
+/** Register engine factory instance. */
+void engine_register(EngineFactory *engine)
 {
 	rlist_add_entry(&engines, engine, link);
 }
 
-/** Find engine by name. */
-struct engine*
+/** Find factory engine by name. */
+EngineFactory*
 engine_find(const char *name)
 {
-	struct engine *e;
+	EngineFactory *e;
 	rlist_foreach_entry(e, &engines, link) {
 		if (strcmp(e->name, name) == 0)
 			return e;
@@ -54,70 +75,21 @@ engine_find(const char *name)
 	tnt_raise(LoggedError, ER_NO_SUCH_ENGINE, name);
 }
 
-/** Init engine instance. */
-void engine_init(struct engine *instance, const char *name)
-{
-	struct engine *origin = engine_find(name);
-	*instance = *origin;
-	instance->origin = origin;
-	instance->link = RLIST_INITIALIZER(instance->link);
-	instance->init(instance);
-}
-
-/** Shutdown all engines. */
-void engine_shutdown()
-{
-	struct engine *e;
-	rlist_foreach_entry(e, &engines, link)
-		e->free(e);
-}
-
 /** Call a visitor function on every registered engine. */
-void engine_foreach(void (*func)(struct engine *engine, void *udata), void *udata)
+void engine_foreach(void (*func)(EngineFactory *engine, void *udata),
+                    void *udata)
 {
-	struct engine *e;
+	EngineFactory *e;
 	rlist_foreach_entry(e, &engines, link)
 		func(e, udata);
 }
 
-/**
- * Derive recovery state from a parent engine
- * handler.
- */
-void engine_derive(struct engine *engine)
+/** Shutdown all engine factories. */
+void engine_shutdown()
 {
-	engine->state   = engine->origin->state;
-	engine->recover = engine->origin->recover;
-	engine->replace = engine->origin->replace;
+	EngineFactory *e, *tmp;
+	rlist_foreach_entry_safe(e, &engines, link, tmp) {
+		e->shutdown();
+		delete e;
+	}
 }
-
-static inline void
-memtx_init(struct engine *engine __attribute((unused)))
-{ }
-
-static inline void
-memtx_free(struct engine *engine __attribute((unused)))
-{ }
-
-/**
- * This is a vtab with which a newly created space which has no
- * keys is primed.
- * At first it is set to correctly work for spaces created during
- * recovery from snapshot. In process of recovery it is updated as
- * below:
- *
- * 1) after SNAP is loaded:
- *    recover = space_build_primary_key
- * 2) when all XLOGs are loaded:
- *    recover = space_build_all_keys
- */
-struct engine engine_memtx = {
-	.name    = "memtx",
-	.origin  = NULL,
-	.state   = READY_NO_KEYS,
-	.recover = space_begin_build_primary_key,
-	.replace = space_replace_no_keys,
-	.init    = memtx_init,
-	.free    = memtx_free,
-	.link    = RLIST_INITIALIZER(engine_memtx.link)
-};
diff --git a/src/box/engine.h b/src/box/engine.h
index 24ada8d662c74fe8e23743f46a9257ffa93bd815..11bccdeab9fb0224834d398cfdb0ba0f8722c378 100644
--- a/src/box/engine.h
+++ b/src/box/engine.h
@@ -32,15 +32,8 @@
 #include "index.h"
 #include <exception.h>
 
-struct tuple;
 struct space;
-
-typedef void (*engine_recover_f)(struct space *space);
-
-typedef struct tuple*
-(*engine_replace_f)(struct space *space,
-                    struct tuple *old_tuple,
-                    struct tuple *new_tuple, enum dup_replace_mode);
+struct tuple;
 
 /** Reflects what space_replace() is supposed to do. */
 enum engine_recovery_state {
@@ -66,9 +59,13 @@ enum engine_recovery_state {
 	READY_ALL_KEYS
 };
 
-struct engine {
-	const char *name;
-	struct engine *origin;
+typedef void (*engine_recover_f)(struct space*);
+
+typedef struct tuple*
+(*engine_replace_f)(struct space*, struct tuple*, struct tuple*,
+                    enum dup_replace_mode);
+
+struct engine_recovery {
 	enum engine_recovery_state state;
 	/* Recover is called after each recover step to enable
 	 * keys. When recovery is complete, it enables all keys
@@ -76,37 +73,59 @@ struct engine {
 	 */
 	engine_recover_f recover;
 	engine_replace_f replace;
+};
 
-	void (*init)(struct engine*);
-	void (*free)(struct engine*);
+struct Engine;
 
+/** Engine instance */
+struct EngineFactory: public Object {
+	EngineFactory(const char *engine_name);
+	virtual ~EngineFactory() {}
+	virtual void init();
+	virtual void shutdown();
+	virtual Engine *open() = 0;
+	virtual void close(Engine*);
+	const char *name;
+	struct engine_recovery recovery;
 	struct rlist link;
 };
 
-extern struct rlist engines;
-
-/** Register engine instance. */
-void engine_register(struct engine *engine);
-
-/** Find engine by name. */
-struct engine *engine_find(const char *name);
-
-/** Init engine instance. */
-void engine_init(struct engine *instance, const char *name);
+/** Engine handle */
+struct Engine: public Object {
+	Engine(EngineFactory *f);
+	virtual ~Engine() {}
+
+	inline struct tuple*
+	replace(struct space *space,
+	        struct tuple *old_tuple,
+	        struct tuple *new_tuple, enum dup_replace_mode mode)
+	{
+		return recovery.replace(space, old_tuple, new_tuple, mode);
+	}
+
+	inline void recover(struct space *space) {
+		recovery.recover(space);
+	}
+
+	inline void recover_derive() {
+		recovery = host->recovery;
+	}
+
+	engine_recovery recovery;
+	EngineFactory *host;
+};
 
-/** Shutdown all engines. */
-void engine_shutdown();
+/** Register engine factory instance. */
+void engine_register(EngineFactory *engine);
 
 /** Call a visitor function on every registered engine. */
-void engine_foreach(void (*func)(struct engine *engine, void *udata),
+void engine_foreach(void (*func)(EngineFactory *engine, void *udata),
                     void *udata);
 
-/**
- * Derive recovery state from a parent engine
- * handler.
- */
-void engine_derive(struct engine *engine);
+/** Find engine factory by name. */
+EngineFactory *engine_find(const char *name);
 
-extern struct engine engine_memtx;
+/** Shutdown all engines factories. */
+void engine_shutdown();
 
 #endif /* TARANTOOL_BOX_ENGINE_H_INCLUDED */
diff --git a/src/box/engine_memtx.cc b/src/box/engine_memtx.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3e3a47a42fa4cc1b6054f19624f8f24c31c18514
--- /dev/null
+++ b/src/box/engine_memtx.cc
@@ -0,0 +1,78 @@
+/*
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "tuple.h"
+#include "engine.h"
+#include "engine_memtx.h"
+#include "space.h"
+#include "exception.h"
+#include "salad/rlist.h"
+#include <stdlib.h>
+#include <string.h>
+
+struct MEMTX_Engine: public Engine {
+	MEMTX_Engine(EngineFactory *e)
+		: Engine(e)
+	{ }
+	virtual ~MEMTX_Engine()
+	{
+		/* do nothing */
+		/* engine->close(this); */
+	}
+};
+
+/**
+ * This is a vtab with which a newly created space which has no
+ * keys is primed.
+ * At first it is set to correctly work for spaces created during
+ * recovery from snapshot. In process of recovery it is updated as
+ * below:
+ *
+ * 1) after SNAP is loaded:
+ *    recover = space_build_primary_key
+ * 2) when all XLOGs are loaded:
+ *    recover = space_build_all_keys
+*/
+static inline void
+memtx_recovery_prepare(struct engine_recovery *r)
+{
+	r->state   = READY_NO_KEYS;
+	r->recover = space_begin_build_primary_key;
+	r->replace = space_replace_no_keys;
+}
+
+MEMTX::MEMTX()
+	:EngineFactory("memtx")
+{
+	memtx_recovery_prepare(&recovery);
+}
+
+Engine *MEMTX::open()
+{
+	return new MEMTX_Engine(this);
+}
diff --git a/src/box/engine_memtx.h b/src/box/engine_memtx.h
new file mode 100644
index 0000000000000000000000000000000000000000..e6d0cbb6a9daf0d03ffb43663531a05713ed18de
--- /dev/null
+++ b/src/box/engine_memtx.h
@@ -0,0 +1,37 @@
+#ifndef TARANTOOL_BOX_ENGINE_MEMTX_H_INCLUDED
+#define TARANTOOL_BOX_ENGINE_MEMTX_H_INCLUDED
+/*
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+struct MEMTX: public EngineFactory {
+	MEMTX();
+	virtual Engine *open();
+};
+
+#endif /* TARANTOOL_BOX_ENGINE_MEMTX_H_INCLUDED */
diff --git a/src/box/schema.cc b/src/box/schema.cc
index e1d04da7c43b172d1de9d920a90e330f9573380f..2e023cfdd86058b65fd8575ae8679d5f39d06f71 100644
--- a/src/box/schema.cc
+++ b/src/box/schema.cc
@@ -166,12 +166,12 @@ static void
 do_one_recover_step(struct space *space, void * /* param */)
 {
 	if (space_index(space, 0)) {
-		space->engine.recover(space);
+		space->engine->recover(space);
 	} else {
 		/* in case of space has no primary index,
 		 * derive it's engine handler recovery state from
 		 * the global one. */
-		engine_derive(&space->engine);
+		space->engine->recover_derive();
 	}
 }
 
@@ -198,9 +198,9 @@ sc_space_new(struct space_def *space_def,
 	 *   ensures validation of tuples when starting from
 	 *   a snapshot of older version.
 	 */
-	space->engine.recover(space); /* load snapshot - begin */
-	space->engine.recover(space); /* load snapshot - end */
-	space->engine.recover(space); /* build secondary keys */
+	space->engine->recover(space); /* load snapshot - begin */
+	space->engine->recover(space); /* load snapshot - end */
+	space->engine->recover(space); /* build secondary keys */
 	return space;
 }
 
@@ -300,10 +300,10 @@ schema_init()
 }
 
 static inline void
-space_end_recover_snapshot_cb(struct engine *engine, void *udate)
+space_end_recover_snapshot_cb(EngineFactory *f, void *udate)
 {
 	(void)udate;
-	engine->recover = space_build_primary_key;
+	f->recovery.recover = space_build_primary_key;
 }
 
 void
@@ -325,10 +325,10 @@ fix_lua(struct space *space, void * /* param */)
 }
 
 static inline void
-space_end_recover_cb(struct engine *engine, void *udate)
+space_end_recover_cb(EngineFactory *f, void *udate)
 {
 	(void)udate;
-	engine->recover = space_build_all_keys;
+	f->recovery.recover = space_build_all_keys;
 }
 
 void
diff --git a/src/box/space.cc b/src/box/space.cc
index 0c930073dacc22bcf2263e25c5667b98672f8e75..b7f3551a7950c258a08f934a80e9fb9c4172f9ca 100644
--- a/src/box/space.cc
+++ b/src/box/space.cc
@@ -77,7 +77,8 @@ space_new(struct space_def *def, struct rlist *key_list)
 	tuple_format_ref(space->format, 1);
 	space->index_id_max = index_id_max;
 	/* init space engine instance */
-	engine_init(&space->engine, def->engine_name);
+	EngineFactory *engine = engine_find(def->engine_name);
+	space->engine = engine->open();
 	/* fill space indexes */
 	rlist_foreach_entry(key_def, key_list, link) {
 		space->index_map[key_def->iid] = Index::factory(key_def);
@@ -95,6 +96,8 @@ space_delete(struct space *space)
 		delete space->index[j];
 	if (space->format)
 		tuple_format_ref(space->format, -1);
+	if (space->engine)
+		delete space->engine;
 
 	struct trigger *trigger, *tmp;
 	rlist_foreach_entry_safe(trigger, &space->on_replace, link, tmp) {
@@ -228,9 +231,10 @@ space_build_secondary_keys(struct space *space)
 			say_info("Space %d: done", space_id(space));
 		}
 	}
-	space->engine.state = READY_ALL_KEYS;
-	space->engine.recover = space_noop; /* mark the end of recover */
-	space->engine.replace = space_replace_all_keys;
+	engine_recovery *r = &space->engine->recovery;
+	r->state   = READY_ALL_KEYS;
+	r->recover = space_noop; /* mark the end of recover */
+	r->replace = space_replace_all_keys;
 }
 
 /** Build the primary key after loading data from a snapshot. */
@@ -238,9 +242,10 @@ void
 space_end_build_primary_key(struct space *space)
 {
 	space->index[0]->endBuild();
-	space->engine.state = READY_PRIMARY_KEY;
-	space->engine.replace = space_replace_primary_key;
-	space->engine.recover = space_build_secondary_keys;
+	engine_recovery *r = &space->engine->recovery;
+	r->state   = READY_PRIMARY_KEY;
+	r->replace = space_replace_primary_key;
+	r->recover = space_build_secondary_keys;
 }
 
 /** Prepare the primary key for bulk load (loading from
@@ -250,8 +255,9 @@ void
 space_begin_build_primary_key(struct space *space)
 {
 	space->index[0]->beginBuild();
-	space->engine.replace = space_replace_build_next;
-	space->engine.recover = space_end_build_primary_key;
+	engine_recovery *r = &space->engine->recovery;
+	r->replace = space_replace_build_next;
+	r->recover = space_end_build_primary_key;
 }
 
 /**
diff --git a/src/box/space.h b/src/box/space.h
index dfbfb7f0c28a727a23d037b2373bfb242e8b35eb..2ea00cfa4c5bfa5ca2b09f4b199abfd8951eeff5 100644
--- a/src/box/space.h
+++ b/src/box/space.h
@@ -42,7 +42,7 @@ struct space {
 	 * life cycle, throughout phases of recovery or with
 	 * deletion and addition of indexes.
 	 */
-	struct engine engine;
+	Engine *engine;
 
 	/** Triggers fired after space_replace() -- see txn_replace(). */
 	struct rlist on_replace;
@@ -183,8 +183,7 @@ static inline struct tuple *
 space_replace(struct space *space, struct tuple *old_tuple,
 	      struct tuple *new_tuple, enum dup_replace_mode mode)
 {
-	return space->engine.replace(space, old_tuple, new_tuple,
-				     mode);
+	return space->engine->replace(space, old_tuple, new_tuple, mode);
 }
 
 struct tuple *