diff --git a/src/box/applier.cc b/src/box/applier.cc
index 4898f9f7bbeddfba73d084bd039655283aea4ab6..40fc5ce8674911775aaf086e2d4cf24e59e5e0da 100644
--- a/src/box/applier.cc
+++ b/src/box/applier.cc
@@ -247,7 +247,7 @@ apply_snapshot_row(struct xrow_header *row)
 	 * Master only sends confirmed rows during join.
 	 */
 	txn_set_flags(txn, TXN_FORCE_ASYNC);
-	if (txn_begin_stmt(txn, space) != 0)
+	if (txn_begin_stmt(txn, space, request.type) != 0)
 		goto rollback;
 	/* no access checks here - applier always works with admin privs */
 	struct tuple *unused;
@@ -277,7 +277,7 @@ process_nop(struct request *request)
 {
 	assert(request->type == IPROTO_NOP);
 	struct txn *txn = in_txn();
-	if (txn_begin_stmt(txn, NULL) != 0)
+	if (txn_begin_stmt(txn, NULL, request->type) != 0)
 		return -1;
 	return txn_commit_stmt(txn, request);
 }
diff --git a/src/box/box.cc b/src/box/box.cc
index 70b3251809b133bd48a8e7610074280e4827ebc3..2d2ae233c4e191ce29d994dc9fe2be7817407f82 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -216,7 +216,7 @@ box_process_rw(struct request *request, struct space *space,
 	rmean_collect(rmean_box, request->type, 1);
 	if (access_check_space(space, PRIV_W) != 0)
 		goto rollback;
-	if (txn_begin_stmt(txn, space) != 0)
+	if (txn_begin_stmt(txn, space, request->type) != 0)
 		goto rollback;
 	if (space_execute_dml(space, txn, request, &tuple) != 0) {
 		txn_rollback_stmt(txn);
diff --git a/src/box/lua/space.cc b/src/box/lua/space.cc
index 8d4d8cc23bcf1e480e2c43a6cc7e8fec1bd276a7..77a589ec44b82ccbd8afdbd43babc588bc870746 100644
--- a/src/box/lua/space.cc
+++ b/src/box/lua/space.cc
@@ -75,9 +75,8 @@ lbox_push_txn_stmt(struct lua_State *L, void *event)
 	}
 	/* @todo: maybe the space object has to be here */
 	lua_pushstring(L, stmt->space->def->name);
-	assert(stmt->row != NULL);
 	/* operation type: INSERT/UPDATE/UPSERT/REPLACE/DELETE */
-	lua_pushstring(L, iproto_type_name(stmt->row->type));
+	lua_pushstring(L, iproto_type_name(stmt->type));
 	return 4;
 }
 
diff --git a/src/box/memtx_engine.c b/src/box/memtx_engine.c
index 763e7d83e81429cdc5b659a38be48f5c77fad313..8e0622f12225ffe00c9f9804e9761af3e2da324d 100644
--- a/src/box/memtx_engine.c
+++ b/src/box/memtx_engine.c
@@ -253,7 +253,7 @@ memtx_engine_recover_snapshot_row(struct memtx_engine *memtx,
 	struct txn *txn = txn_begin();
 	if (txn == NULL)
 		return -1;
-	if (txn_begin_stmt(txn, space) != 0)
+	if (txn_begin_stmt(txn, space, request.type) != 0)
 		goto rollback;
 	/* no access checks here - applier always works with admin privs */
 	struct tuple *unused;
diff --git a/src/box/space.c b/src/box/space.c
index 6d1d771178fbaa0921043e38f57f340f6af53efa..a3adf4bd32a4ce32ae1c99b5dc7f106e1ca1dc84 100644
--- a/src/box/space.c
+++ b/src/box/space.c
@@ -481,15 +481,6 @@ after_old_tuple_lookup:;
 	assert(stmt->old_tuple == NULL && stmt->new_tuple == NULL);
 	stmt->old_tuple = old_tuple;
 	stmt->new_tuple = new_tuple;
-	/*
-	 * A fake row attached to txn_stmt during execution
-	 * of before_replace triggers to store operation type.
-	 * It is pushed to the before_replace trigger in lua.
-	 */
-	struct xrow_header temp_header;
-	temp_header.type = type;
-	assert(stmt->row == NULL);
-	stmt->row = &temp_header;
 
 	int rc = trigger_run(&space->before_replace, txn);
 
@@ -502,7 +493,6 @@ after_old_tuple_lookup:;
 	assert(stmt->old_tuple == old_tuple);
 	stmt->old_tuple = NULL;
 	stmt->new_tuple = NULL;
-	stmt->row = NULL;
 
 	if (rc != 0)
 		goto out;
diff --git a/src/box/txn.c b/src/box/txn.c
index 40061ff0963953a6807c1898545bbc362587c285..959a3c3ee9b1216198956cf68e418e1c02a38f38 100644
--- a/src/box/txn.c
+++ b/src/box/txn.c
@@ -306,7 +306,7 @@ txn_begin_in_engine(struct engine *engine, struct txn *txn)
 }
 
 int
-txn_begin_stmt(struct txn *txn, struct space *space)
+txn_begin_stmt(struct txn *txn, struct space *space, uint16_t type)
 {
 	assert(txn == in_txn());
 	assert(txn != NULL);
@@ -340,6 +340,7 @@ txn_begin_stmt(struct txn *txn, struct space *space)
 		goto fail;
 
 	stmt->space = space;
+	stmt->type = type;
 	if (engine_begin_statement(engine, txn) != 0)
 		goto fail;
 
@@ -418,25 +419,7 @@ txn_commit_stmt(struct txn *txn, struct request *request)
 			 */
 			stmt->does_require_old_tuple = true;
 
-			int rc = 0;
-			if(!space_is_temporary(stmt->space)) {
-				rc = trigger_run(&stmt->space->on_replace, txn);
-			} else {
-				/*
-				 * There is no row attached to txn_stmt for
-				 * temporary spaces, since DML operations on
-				 * them are not written to WAL.
-				 * Fake a row to pass operation type to lua
-				 * on_replace triggers.
-				 */
-				assert(stmt->row == NULL);
-				struct xrow_header temp_header;
-				temp_header.type = request->type;
-				stmt->row = &temp_header;
-				rc = trigger_run(&stmt->space->on_replace, txn);
-				stmt->row = NULL;
-			}
-			if (rc != 0)
+			if(trigger_run(&stmt->space->on_replace, txn) != 0)
 				goto fail;
 		}
 	}
diff --git a/src/box/txn.h b/src/box/txn.h
index a45518064208cefb8141773f4dad1fca1b5303dd..8794335cd623919f37c821a5a3b65edc6ba94176 100644
--- a/src/box/txn.h
+++ b/src/box/txn.h
@@ -212,6 +212,10 @@ struct txn_stmt {
 	 * old_tuple to be NULL.
 	 */
 	bool does_require_old_tuple;
+	/**
+	* Request type - IPROTO type code
+	*/
+	uint16_t type;
 	/** Commit/rollback triggers associated with this statement. */
 	struct rlist on_commit;
 	struct rlist on_rollback;
@@ -557,10 +561,10 @@ txn_n_rows(struct txn *txn)
 }
 
 /**
- * Start a new statement.
+ * Start a new statement in @a space with requst @a type (IPROTO_ constant).
  */
 int
-txn_begin_stmt(struct txn *txn, struct space *space);
+txn_begin_stmt(struct txn *txn, struct space *space, uint16_t type);
 
 int
 txn_begin_in_engine(struct engine *engine, struct txn *txn);
diff --git a/src/box/vy_scheduler.c b/src/box/vy_scheduler.c
index b641dd9b8d4f80e2667f6ce1ac640405089b611c..7d8324a52b1b1f6fae9a44f2458e081ba96fc9ec 100644
--- a/src/box/vy_scheduler.c
+++ b/src/box/vy_scheduler.c
@@ -861,7 +861,7 @@ vy_deferred_delete_process_one(struct space *deferred_delete_space,
 	tuple_unref(delete);
 
 	struct txn *txn = in_txn();
-	if (txn_begin_stmt(txn, deferred_delete_space) != 0)
+	if (txn_begin_stmt(txn, deferred_delete_space, request.type) != 0)
 		return -1;
 
 	struct tuple *unused;