diff --git a/src/benchmark/benchmark_mapblock.cpp b/src/benchmark/benchmark_mapblock.cpp
index 7756233af..440888d16 100644
--- a/src/benchmark/benchmark_mapblock.cpp
+++ b/src/benchmark/benchmark_mapblock.cpp
@@ -26,9 +26,8 @@ typedef std::vector<MapBlock*> MBContainer;
 static void allocateSome(MBContainer &vec, u32 n)
 {
 	vec.reserve(vec.size() + n);
-	Map *map = reinterpret_cast<Map*>(0x1234);
 	for (u32 i = 0; i < n; i++) {
-		auto *mb = new MapBlock(map, {i & 0xff, 0, i >> 8}, nullptr);
+		auto *mb = new MapBlock({i & 0xff, 0, i >> 8}, nullptr);
 		vec.push_back(mb);
 	}
 }
diff --git a/src/main.cpp b/src/main.cpp
index dc98fb74d..d85afe97a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1272,7 +1272,7 @@ static bool recompress_map_database(const GameParams &game_params, const Setting
 		iss.clear();
 
 		{
-			MapBlock mb(nullptr, v3s16(0,0,0), &server);
+			MapBlock mb(v3s16(0,0,0), &server);
 			u8 ver = readU8(iss);
 			mb.deSerialize(iss, ver, true);
 
diff --git a/src/map.cpp b/src/map.cpp
index ae8a24633..c44e31193 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -164,11 +164,11 @@ MapNode Map::getNode(v3s16 p, bool *is_valid_position)
 	return node;
 }
 
-static void set_node_in_block(MapBlock *block, v3s16 relpos, MapNode n)
+static void set_node_in_block(const NodeDefManager *nodedef, MapBlock *block,
+		v3s16 relpos, MapNode n)
 {
 	// Never allow placing CONTENT_IGNORE, it causes problems
 	if(n.getContent() == CONTENT_IGNORE){
-		const NodeDefManager *nodedef = block->getParent()->getNodeDefManager();
 		v3s16 blockpos = block->getPos();
 		v3s16 p = blockpos * MAP_BLOCKSIZE + relpos;
 		errorstream<<"Not allowing to place CONTENT_IGNORE"
@@ -186,7 +186,7 @@ void Map::setNode(v3s16 p, MapNode n)
 	v3s16 blockpos = getNodeBlockPos(p);
 	MapBlock *block = getBlockNoCreate(blockpos);
 	v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
-	set_node_in_block(block, relpos, n);
+	set_node_in_block(m_gamedef->ndef(), block, relpos, n);
 }
 
 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
@@ -215,14 +215,14 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
 		// No light update needed, just copy over the old light.
 		n.setLight(LIGHTBANK_DAY, oldnode.getLightRaw(LIGHTBANK_DAY, oldf), f);
 		n.setLight(LIGHTBANK_NIGHT, oldnode.getLightRaw(LIGHTBANK_NIGHT, oldf), f);
-		set_node_in_block(block, relpos, n);
+		set_node_in_block(m_gamedef->ndef(), block, relpos, n);
 
 		modified_blocks[blockpos] = block;
 	} else {
 		// Ignore light (because calling voxalgo::update_lighting_nodes)
 		n.setLight(LIGHTBANK_DAY, 0, f);
 		n.setLight(LIGHTBANK_NIGHT, 0, f);
-		set_node_in_block(block, relpos, n);
+		set_node_in_block(m_gamedef->ndef(), block, relpos, n);
 
 		// Update lighting
 		std::vector<std::pair<v3s16, MapNode> > oldnodes;
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index bdcc2fe16..ef9b47b9e 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -66,8 +66,7 @@ static const char *modified_reason_strings[] = {
 	MapBlock
 */
 
-MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef):
-		m_parent(parent),
+MapBlock::MapBlock(v3s16 pos, IGameDef *gamedef):
 		m_pos(pos),
 		m_pos_relative(pos * MAP_BLOCKSIZE),
 		data(new MapNode[nodecount]),
@@ -146,25 +145,6 @@ void MapBlock::step(float dtime, const std::function<bool(v3s16, MapNode, f32)>
 	}
 }
 
-bool MapBlock::isValidPositionParent(v3s16 p)
-{
-	if (isValidPosition(p)) {
-		return true;
-	}
-
-	return m_parent->isValidPosition(getPosRelative() + p);
-}
-
-MapNode MapBlock::getNodeParent(v3s16 p, bool *is_valid_position)
-{
-	if (!isValidPosition(p))
-		return m_parent->getNode(getPosRelative() + p, is_valid_position);
-
-	if (is_valid_position)
-		*is_valid_position = true;
-	return data[p.Z * zstride + p.Y * ystride + p.X];
-}
-
 std::string MapBlock::getModifiedReasonString()
 {
 	std::string reason;
diff --git a/src/mapblock.h b/src/mapblock.h
index 54b118e64..1778aef8b 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -72,30 +72,20 @@ class VoxelManipulator;
 class MapBlock
 {
 public:
-	MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef);
+	MapBlock(v3s16 pos, IGameDef *gamedef);
 	~MapBlock();
 
-	/*virtual u16 nodeContainerId() const
-	{
-		return NODECONTAINER_ID_MAPBLOCK;
-	}*/
-
-	Map *getParent()
-	{
-		return m_parent;
-	}
-
 	// Any server-modding code can "delete" arbitrary blocks (i.e. with
 	// core.delete_area), which makes them orphan. Avoid using orphan blocks for
 	// anything.
 	bool isOrphan() const
 	{
-		return !m_parent;
+		return m_orphan;
 	}
 
 	void makeOrphan()
 	{
-		m_parent = nullptr;
+		m_orphan = true;
 	}
 
 	void reallocate()
@@ -310,11 +300,6 @@ public:
 		setNodeNoCheck(p.X, p.Y, p.Z, n);
 	}
 
-	// These functions consult the parent container if the position
-	// is not valid on this MapBlock.
-	bool isValidPositionParent(v3s16 p);
-	MapNode getNodeParent(v3s16 p, bool *is_valid_position = NULL);
-
 	// Copies data to VoxelManipulator to getPosRelative()
 	void copyTo(VoxelManipulator &dst);
 
@@ -491,8 +476,6 @@ private:
 		Private member variables
 	*/
 
-	// NOTE: Lots of things rely on this being the Map
-	Map *m_parent;
 	// Position in blocks on parent
 	v3s16 m_pos;
 
@@ -545,6 +528,9 @@ private:
 	bool m_day_night_differs = false;
 	bool m_day_night_differs_expired = true;
 
+	// see isOrphan()
+	bool m_orphan = false;
+	// Whether mapgen has generated the content of this block (persisted)
 	bool m_generated = false;
 
 	/*
diff --git a/src/mapsector.cpp b/src/mapsector.cpp
index e966f77d2..0eaf81ed4 100644
--- a/src/mapsector.cpp
+++ b/src/mapsector.cpp
@@ -73,7 +73,7 @@ std::unique_ptr<MapBlock> MapSector::createBlankBlockNoInsert(s16 y)
 
 	v3s16 blockpos_map(m_pos.X, y, m_pos.Y);
 
-	return std::make_unique<MapBlock>(m_parent, blockpos_map, m_gamedef);
+	return std::make_unique<MapBlock>(blockpos_map, m_gamedef);
 }
 
 MapBlock *MapSector::createBlankBlock(s16 y)