diff --git a/core/state_processor.go b/core/state_processor.go
index 90f5a4f60c901bd8736f8f67cbe52e8ce7728ddb..4489cfce25440f80ec8f6c891020c157f38e1196 100644
--- a/core/state_processor.go
+++ b/core/state_processor.go
@@ -104,11 +104,17 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common
 	}
 
 	// Update the state with pending changes
+	var root []byte
+	if config.IsMetropolis(header.Number) {
+		statedb.Finalise()
+	} else {
+		root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes()
+	}
 	usedGas.Add(usedGas, gas)
+
 	// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
 	// based on the eip phase, we're passing wether the root touch-delete accounts.
-	root := statedb.IntermediateRoot(config.IsEIP158(header.Number))
-	receipt := types.NewReceipt(root.Bytes(), usedGas)
+	receipt := types.NewReceipt(root, usedGas)
 	receipt.TxHash = tx.Hash()
 	receipt.GasUsed = new(big.Int).Set(gas)
 	// if the transaction created a contract, store the creation address in the receipt.
diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go
index edbd64ba4e3e7d01c76a5150e0b1682a55a10a95..eb2e5d42b4210f1fdc4ce20dfbdb36285da68d39 100644
--- a/core/types/gen_receipt_json.go
+++ b/core/types/gen_receipt_json.go
@@ -13,7 +13,7 @@ import (
 
 func (r Receipt) MarshalJSON() ([]byte, error) {
 	type Receipt struct {
-		PostState         hexutil.Bytes  `json:"root"              gencodec:"required"`
+		PostState         hexutil.Bytes  `json:"root"`
 		CumulativeGasUsed *hexutil.Big   `json:"cumulativeGasUsed" gencodec:"required"`
 		Bloom             Bloom          `json:"logsBloom"         gencodec:"required"`
 		Logs              []*Log         `json:"logs"              gencodec:"required"`
@@ -34,7 +34,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
 
 func (r *Receipt) UnmarshalJSON(input []byte) error {
 	type Receipt struct {
-		PostState         hexutil.Bytes   `json:"root"              gencodec:"required"`
+		PostState         hexutil.Bytes   `json:"root"`
 		CumulativeGasUsed *hexutil.Big    `json:"cumulativeGasUsed" gencodec:"required"`
 		Bloom             *Bloom          `json:"logsBloom"         gencodec:"required"`
 		Logs              []*Log          `json:"logs"              gencodec:"required"`
@@ -46,10 +46,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
 	if err := json.Unmarshal(input, &dec); err != nil {
 		return err
 	}
-	if dec.PostState == nil {
-		return errors.New("missing required field 'root' for Receipt")
+	if dec.PostState != nil {
+		r.PostState = dec.PostState
 	}
-	r.PostState = dec.PostState
 	if dec.CumulativeGasUsed == nil {
 		return errors.New("missing required field 'cumulativeGasUsed' for Receipt")
 	}
diff --git a/core/types/receipt.go b/core/types/receipt.go
index ef6f6a2bb2287ddda70d8f5fcbc463af44fb894f..c9906b0154e59c590188bf25437eb5610c03d396 100644
--- a/core/types/receipt.go
+++ b/core/types/receipt.go
@@ -31,7 +31,7 @@ import (
 // Receipt represents the results of a transaction.
 type Receipt struct {
 	// Consensus fields
-	PostState         []byte   `json:"root"              gencodec:"required"`
+	PostState         []byte   `json:"root"`
 	CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"`
 	Bloom             Bloom    `json:"logsBloom"         gencodec:"required"`
 	Logs              []*Log   `json:"logs"              gencodec:"required"`
@@ -48,35 +48,88 @@ type receiptMarshaling struct {
 	GasUsed           *hexutil.Big
 }
 
+// homesteadReceiptRLP contains the receipt's Homestead consensus fields, used
+// during RLP serialization.
+type homesteadReceiptRLP struct {
+	PostState         []byte
+	CumulativeGasUsed *big.Int
+	Bloom             Bloom
+	Logs              []*Log
+}
+
+// metropolisReceiptRLP contains the receipt's Metropolis consensus fields, used
+// during RLP serialization.
+type metropolisReceiptRLP struct {
+	CumulativeGasUsed *big.Int
+	Bloom             Bloom
+	Logs              []*Log
+}
+
 // NewReceipt creates a barebone transaction receipt, copying the init fields.
 func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt {
 	return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)}
 }
 
 // EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
-// into an RLP stream.
+// into an RLP stream. If no post state is present, metropolis fork is assumed.
 func (r *Receipt) EncodeRLP(w io.Writer) error {
-	return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs})
+	if r.PostState == nil {
+		return rlp.Encode(w, &metropolisReceiptRLP{r.CumulativeGasUsed, r.Bloom, r.Logs})
+	}
+	return rlp.Encode(w, &homesteadReceiptRLP{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs})
 }
 
 // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
 // from an RLP stream.
 func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
-	var receipt struct {
-		PostState         []byte
-		CumulativeGasUsed *big.Int
-		Bloom             Bloom
-		Logs              []*Log
+	// Load the raw bytes since we have multiple possible formats
+	raw, err := s.Raw()
+	if err != nil {
+		return err
 	}
-	if err := s.Decode(&receipt); err != nil {
+	list, _, err := rlp.SplitList(raw)
+	if err != nil {
 		return err
 	}
-	r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom, receipt.Logs
-	return nil
+	items, err := rlp.CountValues(list)
+	if err != nil {
+		return err
+	}
+	// Deserialize based on the number of content items
+	switch items {
+	case 3:
+		// Metropolis receipts have 3 components
+		var metro metropolisReceiptRLP
+		if err := rlp.DecodeBytes(raw, &metro); err != nil {
+			return err
+		}
+		r.CumulativeGasUsed = metro.CumulativeGasUsed
+		r.Bloom = metro.Bloom
+		r.Logs = metro.Logs
+		return nil
+
+	case 4:
+		// Homestead receipts have 4 components
+		var home homesteadReceiptRLP
+		if err := rlp.DecodeBytes(raw, &home); err != nil {
+			return err
+		}
+		r.PostState = home.PostState[:]
+		r.CumulativeGasUsed = home.CumulativeGasUsed
+		r.Bloom = home.Bloom
+		r.Logs = home.Logs
+		return nil
+
+	default:
+		return fmt.Errorf("invalid receipt components: %v", items)
+	}
 }
 
 // String implements the Stringer interface.
 func (r *Receipt) String() string {
+	if r.PostState == nil {
+		return fmt.Sprintf("receipt{cgas=%v bloom=%x logs=%v}", r.CumulativeGasUsed, r.Bloom, r.Logs)
+	}
 	return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs)
 }
 
diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go
index 45bb873225273506ee07abc5e3560bf8b9aea58e..02df03fff458a2853d03b6aa85b76cc8f4c77aa2 100644
--- a/ethclient/ethclient.go
+++ b/ethclient/ethclient.go
@@ -203,8 +203,6 @@ func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*
 	if err == nil {
 		if r == nil {
 			return nil, ethereum.NotFound
-		} else if len(r.PostState) == 0 {
-			return nil, fmt.Errorf("server returned receipt without post state")
 		}
 	}
 	return r, err