diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp
index 5a2b69356..1ffe0f363 100644
--- a/src/query/plan/operator.cpp
+++ b/src/query/plan/operator.cpp
@@ -246,12 +246,14 @@ std::unique_ptr<Cursor> ScanAllByLabel::MakeCursor(GraphDbAccessor &db) {
       output_symbol_, input_->MakeCursor(db), std::move(vertices));
 }
 
-Expand::Expand(const NodeAtom *node_atom, const EdgeAtom *edge_atom,
+Expand::Expand(Symbol node_symbol, Symbol edge_symbol,
+               EdgeAtom::Direction direction,
                const std::shared_ptr<LogicalOperator> &input,
                Symbol input_symbol, bool existing_node, bool existing_edge,
                GraphView graph_view)
-    : node_atom_(node_atom),
-      edge_atom_(edge_atom),
+    : node_symbol_(node_symbol),
+      edge_symbol_(edge_symbol),
+      direction_(direction),
       input_(input ? input : std::make_shared<Once>()),
       input_symbol_(input_symbol),
       existing_node_(existing_node),
@@ -285,8 +287,7 @@ bool Expand::ExpandCursor::Pull(Frame &frame, const SymbolTable &symbol_table) {
       // when expanding in EdgeAtom::Direction::BOTH directions
       // we should do only one expansion for cycles, and it was
       // already done in the block above
-      if (self_.edge_atom_->direction_ == EdgeAtom::Direction::BOTH &&
-          edge.is_cycle())
+      if (self_.direction_ == EdgeAtom::Direction::BOTH && edge.is_cycle())
         continue;
       if (HandleExistingEdge(edge, frame, symbol_table) &&
           PullNode(edge, EdgeAtom::Direction::RIGHT, frame, symbol_table))
@@ -334,7 +335,7 @@ bool Expand::ExpandCursor::InitEdges(Frame &frame,
       break;
   }
 
-  auto direction = self_.edge_atom_->direction_;
+  auto direction = self_.direction_;
   if (direction == EdgeAtom::Direction::LEFT ||
       direction == EdgeAtom::Direction::BOTH) {
     in_edges_ = std::make_unique<InEdgeT>(vertex.in());
@@ -359,14 +360,13 @@ bool Expand::ExpandCursor::HandleExistingEdge(const EdgeAccessor &new_edge,
                                               Frame &frame,
                                               const SymbolTable &symbol_table) {
   if (self_.existing_edge_) {
-    TypedValue &old_edge_value =
-        frame[symbol_table.at(*self_.edge_atom_->identifier_)];
+    TypedValue &old_edge_value = frame[self_.edge_symbol_];
     // old_edge_value may be Null when using optional matching
     return !old_edge_value.IsNull() &&
            old_edge_value.Value<EdgeAccessor>() == new_edge;
   } else {
     // not matching existing, so put the new_edge into the frame and return true
-    frame[symbol_table.at(*self_.edge_atom_->identifier_)] = new_edge;
+    frame[self_.edge_symbol_] = new_edge;
     return true;
   }
 }
@@ -388,14 +388,13 @@ bool Expand::ExpandCursor::HandleExistingNode(const VertexAccessor new_node,
                                               Frame &frame,
                                               const SymbolTable &symbol_table) {
   if (self_.existing_node_) {
-    TypedValue &old_node_value =
-        frame[symbol_table.at(*self_.node_atom_->identifier_)];
+    TypedValue &old_node_value = frame[self_.node_symbol_];
     // old_node_value may be Null when using optional matching
     return !old_node_value.IsNull() &&
            old_node_value.Value<VertexAccessor>() == new_node;
   } else {
-    // not matching existing, so put the new_edge into the frame and return true
-    frame[symbol_table.at(*self_.node_atom_->identifier_)] = new_node;
+    // not matching existing, so put the new_node into the frame and return true
+    frame[self_.node_symbol_] = new_node;
     return true;
   }
 }
diff --git a/src/query/plan/operator.hpp b/src/query/plan/operator.hpp
index 70010420b..7445bb3ed 100644
--- a/src/query/plan/operator.hpp
+++ b/src/query/plan/operator.hpp
@@ -358,18 +358,21 @@ class Expand : public LogicalOperator {
    * the expansion originates from. This is controlled with a
    * constructor argument.
    *
-   * @param node_atom Describes the node to be expanded. Only the
-   *    identifier is used, labels and properties are ignored.
-   * @param edge_atom Describes the edge to be expanded. Identifier
-   *    and direction are used, edge type and properties are ignored.
+   * @param node_symbol Symbol pointing to the node to be expanded. This is
+   *    where the new node will be stored.
+   * @param edge_symbol Symbol for the edge to be expanded. This is where the
+   *    edge value will be stored.
+   * @param direction EdgeAtom::Direction determining the direction of edge
+   *    expansion. The direction is relative to the starting vertex (pointed by
+   *    `input_symbol`).
    * @param input Optional LogicalOperator that preceeds this one.
-   * @param input_symbol Symbol that points to a VertexAccessor
-   *    in the Frame that expansion should emanate from.
-   * @param existing_node If or not the node to be expanded is already
-   *    present in the Frame and should just be checked for equality.
-   * @param existing_edge Same like 'existing_node', but for edges.
+   * @param input_symbol Symbol that points to a VertexAccessor in the Frame
+   *    that expansion should emanate from.
+   * @param existing_node If or not the node to be expanded is already present
+   *    in the Frame and should just be checked for equality.
+   * @param existing_edge Same like `existing_node`, but for edges.
    */
-  Expand(const NodeAtom *node_atom, const EdgeAtom *edge_atom,
+  Expand(Symbol node_symbol, Symbol edge_symbol, EdgeAtom::Direction direction,
          const std::shared_ptr<LogicalOperator> &input, Symbol input_symbol,
          bool existing_node, bool existing_edge,
          GraphView graph_view = GraphView::AS_IS);
@@ -378,8 +381,9 @@ class Expand : public LogicalOperator {
 
  private:
   // info on what's getting expanded
-  const NodeAtom *node_atom_;
-  const EdgeAtom *edge_atom_;
+  const Symbol node_symbol_;
+  const Symbol edge_symbol_;
+  const EdgeAtom::Direction direction_;
 
   // the input op and the symbol under which the op's result
   // can be found in the frame
diff --git a/src/query/plan/planner.cpp b/src/query/plan/planner.cpp
index bc744a24f..cb673f934 100644
--- a/src/query/plan/planner.cpp
+++ b/src/query/plan/planner.cpp
@@ -793,7 +793,7 @@ LogicalOperator *PlanMatching(const Matching &matching,
         context.new_symbols.emplace_back(edge_symbol);
       }
       last_op =
-          new Expand(expansion.node2, expansion.edge,
+          new Expand(node_symbol, edge_symbol, expansion.edge->direction_,
                      std::shared_ptr<LogicalOperator>(last_op), node1_symbol,
                      existing_node, existing_edge, context.graph_view);
       if (!existing_edge) {
diff --git a/tests/unit/query_plan_common.hpp b/tests/unit/query_plan_common.hpp
index fa6bcfa22..e333cd15c 100644
--- a/tests/unit/query_plan_common.hpp
+++ b/tests/unit/query_plan_common.hpp
@@ -139,8 +139,9 @@ ExpandTuple MakeExpand(AstTreeStorage &storage, SymbolTable &symbol_table,
   auto node_sym = symbol_table.CreateSymbol(node_identifier, true);
   symbol_table[*node->identifier_] = node_sym;
 
-  auto op = std::make_shared<Expand>(node, edge, input, input_symbol,
-                                     existing_node, existing_edge, graph_view);
+  auto op = std::make_shared<Expand>(node_sym, edge_sym, direction, input,
+                                     input_symbol, existing_node, existing_edge,
+                                     graph_view);
 
   return ExpandTuple{edge, edge_sym, node, node_sym, op};
 }
diff --git a/tests/unit/query_plan_match_filter_return.cpp b/tests/unit/query_plan_match_filter_return.cpp
index da1400c56..9f14bea86 100644
--- a/tests/unit/query_plan_match_filter_return.cpp
+++ b/tests/unit/query_plan_match_filter_return.cpp
@@ -409,12 +409,14 @@ TEST(QueryPlan, OptionalMatchThenExpandToMissingNode) {
   auto with = MakeProduce(optional, n_ne);
   // MATCH (m) -[r]-> (n)
   auto m = MakeScanAll(storage, symbol_table, "m", with);
-  auto edge = EDGE("r", EdgeAtom::Direction::RIGHT);
-  symbol_table[*edge->identifier_] = symbol_table.CreateSymbol("r", true);
+  auto edge_direction = EdgeAtom::Direction::RIGHT;
+  auto edge = EDGE("r", edge_direction);
+  auto edge_sym = symbol_table.CreateSymbol("r", true);
+  symbol_table[*edge->identifier_] = edge_sym;
   auto node = NODE("n");
   symbol_table[*node->identifier_] = with_n_sym;
-  auto expand =
-      std::make_shared<plan::Expand>(node, edge, m.op_, m.sym_, true, false);
+  auto expand = std::make_shared<plan::Expand>(
+      with_n_sym, edge_sym, edge_direction, m.op_, m.sym_, true, false);
   // RETURN m
   auto m_ne = NEXPR("m", IDENT("m"));
   symbol_table[*m_ne->expression_] = m.sym_;
@@ -452,17 +454,19 @@ TEST(QueryPlan, OptionalMatchThenExpandToMissingEdge) {
   // WITH r
   auto r_ne = NEXPR("r", IDENT("r"));
   symbol_table[*r_ne->expression_] = r_m.edge_sym_;
-  auto with_n_sym = symbol_table.CreateSymbol("r", true);
-  symbol_table[*r_ne] = with_n_sym;
+  auto with_r_sym = symbol_table.CreateSymbol("r", true);
+  symbol_table[*r_ne] = with_r_sym;
   auto with = MakeProduce(optional, r_ne);
   // MATCH (a) -[r]- (b)
   auto a = MakeScanAll(storage, symbol_table, "a", with);
-  auto edge = EDGE("r", EdgeAtom::Direction::BOTH);
-  symbol_table[*edge->identifier_] = r_m.edge_sym_;
+  auto edge_direction = EdgeAtom::Direction::BOTH;
+  auto edge = EDGE("r", edge_direction);
+  symbol_table[*edge->identifier_] = with_r_sym;
   auto node = NODE("n");
-  symbol_table[*node->identifier_] = symbol_table.CreateSymbol("b", true);
-  auto expand =
-      std::make_shared<plan::Expand>(node, edge, a.op_, a.sym_, false, true);
+  auto node_sym = symbol_table.CreateSymbol("b", true);
+  symbol_table[*node->identifier_] = node_sym;
+  auto expand = std::make_shared<plan::Expand>(
+      node_sym, with_r_sym, edge_direction, a.op_, a.sym_, false, true);
   // RETURN a
   auto a_ne = NEXPR("a", IDENT("a"));
   symbol_table[*a_ne->expression_] = a.sym_;
@@ -494,8 +498,9 @@ TEST(QueryPlan, ExpandExistingNode) {
         MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
                    EdgeAtom::Direction::RIGHT, false, "n", with_existing);
     if (with_existing)
-      symbol_table[*r_n.node_->identifier_] =
-          symbol_table[*n.node_->identifier_];
+      r_n.op_ =
+          std::make_shared<Expand>(n.sym_, r_n.edge_sym_, r_n.edge_->direction_,
+                                   n.op_, n.sym_, with_existing, false);
 
     // make a named expression and a produce
     auto output = NEXPR("n", IDENT("n"));
@@ -538,8 +543,9 @@ TEST(QueryPlan, ExpandExistingEdge) {
     auto r_k = MakeExpand(storage, symbol_table, r_j.op_, r_j.node_sym_, "r",
                           EdgeAtom::Direction::BOTH, with_existing, "k", false);
     if (with_existing)
-      symbol_table[*r_k.edge_->identifier_] =
-          symbol_table[*r_j.edge_->identifier_];
+      r_k.op_ = std::make_shared<Expand>(r_k.node_sym_, r_j.edge_sym_,
+                                         r_k.edge_->direction_, r_j.op_,
+                                         r_j.node_sym_, false, with_existing);
 
     // make a named expression and a produce
     auto output = NEXPR("r", IDENT("r"));