diff --git a/dapps/faucet/packages/faucet_test.go b/dapps/faucet/packages/faucet_test.go
index 2dfda0bc95086f2f571b1e192bf117ed78b42857..0cb37730e62dd5642de4a2dcd1152184347c64a4 100644
--- a/dapps/faucet/packages/faucet_test.go
+++ b/dapps/faucet/packages/faucet_test.go
@@ -4,6 +4,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
@@ -41,7 +42,7 @@ func TestIsFaucetReq(t *testing.T) {
 		time.Now(),
 		local.PublicKey(),
 		0,
-		tangle.NewDataPayload([]byte("data")),
+		payload.NewGenericDataPayload([]byte("data")),
 		0,
 		ed25519.EmptySignature,
 	)
diff --git a/dapps/faucet/packages/payload/payload.go b/dapps/faucet/packages/payload/payload.go
index f9e73a977d61b26f327a53cbf67406b262902d44..f282bb832ef3ad4cabdd294a8101309f06796652 100644
--- a/dapps/faucet/packages/payload/payload.go
+++ b/dapps/faucet/packages/payload/payload.go
@@ -5,6 +5,7 @@ import (
 	"crypto"
 	"fmt"
 
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	// Only want to use init
 	_ "golang.org/x/crypto/blake2b"
 
@@ -23,13 +24,13 @@ const (
 
 // Payload represents a request which contains an address for the faucet to send funds to.
 type Payload struct {
-	payloadType tangle.PayloadType
+	payloadType payload.Type
 	address     address.Address
 	nonce       uint64
 }
 
 // Type represents the identifier for the faucet Payload type.
-var Type = tangle.PayloadType(2)
+var Type = payload.NewType(2, ObjectName, PayloadUnmarshaler)
 var powWorker = pow.New(crypto.BLAKE2b_512, 1)
 
 // New is the constructor of a Payload and creates a new Payload object from the given details.
@@ -50,10 +51,6 @@ func New(addr address.Address, powTarget int) (*Payload, error) {
 	return p, nil
 }
 
-func init() {
-	tangle.RegisterPayloadType(Type, ObjectName, PayloadUnmarshaler)
-}
-
 // FromBytes parses the marshaled version of a Payload into an object.
 // It either returns a new Payload or fills an optionally provided Payload with the parsed information.
 func FromBytes(bytes []byte) (result *Payload, consumedBytes int, err error) {
@@ -66,7 +63,7 @@ func FromBytes(bytes []byte) (result *Payload, consumedBytes int, err error) {
 		err = fmt.Errorf("failed to unmarshal payload size of faucet payload from bytes: %w", err)
 		return
 	}
-	result.payloadType, err = marshalUtil.ReadUint32()
+	result.payloadType, err = payload.TypeFromMarshalUtil(marshalUtil)
 	if err != nil {
 		err = fmt.Errorf("failed to unmarshal payload type of faucet payload from bytes: %w", err)
 		return
@@ -95,7 +92,7 @@ func FromBytes(bytes []byte) (result *Payload, consumedBytes int, err error) {
 }
 
 // Type returns the type of the faucet Payload.
-func (p *Payload) Type() tangle.PayloadType {
+func (p *Payload) Type() payload.Type {
 	return p.payloadType
 }
 
@@ -111,7 +108,7 @@ func (p *Payload) Bytes() []byte {
 
 	// marshal the payload specific information
 	marshalUtil.WriteUint32(uint32(address.Length + pow.NonceBytes))
-	marshalUtil.WriteUint32(p.Type())
+	marshalUtil.WriteBytes(p.Type().Bytes())
 	marshalUtil.WriteBytes(p.address.Bytes())
 	marshalUtil.WriteUint64(p.nonce)
 
@@ -127,7 +124,7 @@ func (p *Payload) String() string {
 }
 
 // PayloadUnmarshaler sets the generic unmarshaler.
-func PayloadUnmarshaler(data []byte) (payload tangle.Payload, err error) {
+func PayloadUnmarshaler(data []byte) (payload payload.Payload, err error) {
 	payload, _, err = FromBytes(data)
 	if err != nil {
 		err = fmt.Errorf("failed to unmarshal faucet payload from bytes: %w", err)
diff --git a/dapps/valuetransfers/packages/payload/payload.go b/dapps/valuetransfers/packages/payload/payload.go
index 5db6de0388715fd27eaf456eb8ca9e99a52f29f0..914925cbd416019cab51bcdf6b644d1c6f80e2a7 100644
--- a/dapps/valuetransfers/packages/payload/payload.go
+++ b/dapps/valuetransfers/packages/payload/payload.go
@@ -4,13 +4,13 @@ import (
 	"fmt"
 	"sync"
 
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
 	"github.com/iotaledger/hive.go/stringify"
 	"golang.org/x/crypto/blake2b"
 
 	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction"
-	"github.com/iotaledger/goshimmer/packages/tangle"
 )
 
 const (
@@ -184,10 +184,14 @@ func (p *Payload) String() string {
 // region Payload implementation ///////////////////////////////////////////////////////////////////////////////////////
 
 // Type represents the identifier which addresses the value Payload type.
-const Type = tangle.PayloadType(1)
+var Type = payload.NewType(1, ObjectName, func(data []byte) (payload payload.Payload, err error) {
+	payload, _, err = FromBytes(data)
+
+	return
+})
 
 // Type returns the type of the Payload.
-func (p *Payload) Type() tangle.PayloadType {
+func (p *Payload) Type() payload.Type {
 	return Type
 }
 
@@ -221,7 +225,7 @@ func (p *Payload) ObjectStorageValue() (bytes []byte) {
 	payloadLength := IDLength + IDLength + len(transferBytes)
 	marshalUtil := marshalutil.New(marshalutil.UINT32_SIZE + marshalutil.UINT32_SIZE + payloadLength)
 	marshalUtil.WriteUint32(uint32(payloadLength))
-	marshalUtil.WriteUint32(Type)
+	marshalUtil.WriteBytes(Type.Bytes())
 	marshalUtil.WriteBytes(p.parent1PayloadID.Bytes())
 	marshalUtil.WriteBytes(p.parent2PayloadID.Bytes())
 	marshalUtil.WriteBytes(transferBytes)
@@ -233,16 +237,8 @@ func (p *Payload) ObjectStorageValue() (bytes []byte) {
 	return
 }
 
-func init() {
-	tangle.RegisterPayloadType(Type, ObjectName, func(data []byte) (payload tangle.Payload, err error) {
-		payload, _, err = FromBytes(data)
-
-		return
-	})
-}
-
 // define contract (ensure that the struct fulfills the corresponding interface)
-var _ tangle.Payload = &Payload{}
+var _ payload.Payload = &Payload{}
 
 // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
diff --git a/dapps/valuetransfers/packages/tangle/signature_filter_test.go b/dapps/valuetransfers/packages/tangle/signature_filter_test.go
index 1cb93f673908da24bd03d4af3b11811f10938252..0b388a7a5fc2b2183120bc814f611410add38f6f 100644
--- a/dapps/valuetransfers/packages/tangle/signature_filter_test.go
+++ b/dapps/valuetransfers/packages/tangle/signature_filter_test.go
@@ -10,6 +10,7 @@ import (
 	valuePayload "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/payload"
 	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction"
 	"github.com/iotaledger/goshimmer/packages/tangle"
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/autopeering/peer"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/iotaledger/hive.go/identity"
@@ -80,14 +81,14 @@ func TestSignatureFilter(t *testing.T) {
 	// 3. test message with an invalid value payload
 	{
 		// create a data payload
-		marshalUtil := marshalutil.New(tangle.NewDataPayload([]byte("test")).Bytes())
+		marshalUtil := marshalutil.New(payload.NewGenericDataPayload([]byte("test")).Bytes())
 
 		// set the type to be a value payload
 		marshalUtil.WriteSeek(4)
-		marshalUtil.WriteUint32(valuePayload.Type)
+		marshalUtil.WriteBytes(valuePayload.Type.Bytes())
 
 		// parse modified bytes back into a payload object
-		dataPayload, _, err := tangle.DataPayloadFromBytes(marshalUtil.Bytes())
+		dataPayload, _, err := payload.GenericDataPayloadFromBytes(marshalUtil.Bytes())
 		require.NoError(t, err)
 
 		// parse message bytes
diff --git a/packages/drng/collective_beacon_payload.go b/packages/drng/collective_beacon_payload.go
index 08aa611ad1ce3ea803436e8534357dc79d0a2393..a0ed1f829468000514de7b3490b363ec3987397f 100644
--- a/packages/drng/collective_beacon_payload.go
+++ b/packages/drng/collective_beacon_payload.go
@@ -4,9 +4,9 @@ import (
 	"fmt"
 	"sync"
 
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/stringify"
 
-	"github.com/iotaledger/goshimmer/packages/tangle"
 	"github.com/iotaledger/hive.go/marshalutil"
 )
 
@@ -131,7 +131,7 @@ func (p *CollectiveBeaconPayload) Bytes() (bytes []byte) {
 	payloadLength := HeaderLength + marshalutil.UINT64_SIZE + SignatureSize*2 + PublicKeySize
 	marshalUtil := marshalutil.New(marshalutil.UINT32_SIZE + marshalutil.UINT32_SIZE + payloadLength)
 	marshalUtil.WriteUint32(uint32(payloadLength))
-	marshalUtil.WriteUint32(PayloadType)
+	marshalUtil.WriteBytes(PayloadType.Bytes())
 	marshalUtil.WriteBytes(p.Header.Bytes())
 	marshalUtil.WriteUint64(p.Round)
 	marshalUtil.WriteBytes(p.PrevSignature)
@@ -160,7 +160,7 @@ func (p *CollectiveBeaconPayload) String() string {
 // region Payload implementation ///////////////////////////////////////////////////////////////////////////////////////
 
 // Type returns the collective beacon payload type.
-func (p *CollectiveBeaconPayload) Type() tangle.PayloadType {
+func (p *CollectiveBeaconPayload) Type() payload.Type {
 	return PayloadType
 }
 
diff --git a/packages/drng/payload.go b/packages/drng/payload.go
index 0b66bb18089df8906480a2542d1f139afc63ba4f..7abd6532d8e2d930d72b2dcb332c61600dc9b66f 100644
--- a/packages/drng/payload.go
+++ b/packages/drng/payload.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"sync"
 
-	"github.com/iotaledger/goshimmer/packages/tangle"
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/stringify"
 )
@@ -106,7 +106,7 @@ func (p *Payload) Bytes() (bytes []byte) {
 
 	// marshal the payload specific information
 	marshalUtil.WriteUint32(uint32(len(p.Data) + HeaderLength))
-	marshalUtil.WriteUint32(PayloadType)
+	marshalUtil.WriteBytes(PayloadType.Bytes())
 	marshalUtil.WriteBytes(p.Header.Bytes())
 	marshalUtil.WriteBytes(p.Data[:])
 
@@ -126,10 +126,14 @@ func (p *Payload) String() string {
 // region Payload implementation ///////////////////////////////////////////////////////////////////////////////////////
 
 // PayloadType defines the type of the drng payload.
-var PayloadType = tangle.PayloadType(111)
+var PayloadType = payload.NewType(111, ObjectName, func(data []byte) (payload payload.Payload, err error) {
+	payload, _, err = FromBytes(data)
+
+	return
+})
 
 // Type returns the type of the drng payload.
-func (p *Payload) Type() tangle.PayloadType {
+func (p *Payload) Type() payload.Type {
 	return PayloadType
 }
 
@@ -138,12 +142,4 @@ func (p *Payload) Marshal() (bytes []byte, err error) {
 	return p.Bytes(), nil
 }
 
-func init() {
-	tangle.RegisterPayloadType(PayloadType, ObjectName, func(data []byte) (payload tangle.Payload, err error) {
-		payload, _, err = FromBytes(data)
-
-		return
-	})
-}
-
 // // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/packages/spammer/spammer.go b/packages/spammer/spammer.go
index 42f333e35c0e129df59cccbc4a6ea41fdcfea5ac..376e29a956ecb0fb77d0db3251a2816e47369fc6 100644
--- a/packages/spammer/spammer.go
+++ b/packages/spammer/spammer.go
@@ -4,13 +4,14 @@ import (
 	"sync/atomic"
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/types"
 
 	"github.com/iotaledger/goshimmer/packages/tangle"
 )
 
 // IssuePayloadFunc is a function which issues a payload.
-type IssuePayloadFunc = func(payload tangle.Payload) (*tangle.Message, error)
+type IssuePayloadFunc = func(payload payload.Payload) (*tangle.Message, error)
 
 // Spammer spams messages with a static data payload.
 type Spammer struct {
@@ -48,7 +49,7 @@ func (spammer *Spammer) run(rate int, timeUnit time.Duration, processID int64) {
 		}
 
 		// we don't care about errors or the actual issued message
-		_, _ = spammer.issuePayloadFunc(tangle.NewDataPayload([]byte("SPAM")))
+		_, _ = spammer.issuePayloadFunc(payload.NewGenericDataPayload([]byte("SPAM")))
 
 		currentSentCounter++
 
diff --git a/packages/tangle/message.go b/packages/tangle/message.go
index fecb7c7a68c2508d9700b4f143be742585cb48e2..fbecedf1fbbd939db819c0dea03835262b79c80b 100644
--- a/packages/tangle/message.go
+++ b/packages/tangle/message.go
@@ -5,6 +5,7 @@ import (
 	"sync"
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/crypto/ed25519"
 	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/objectstorage"
@@ -19,6 +20,9 @@ const (
 
 	// MessageIDLength defines the length of an MessageID.
 	MessageIDLength = 64
+
+	// ContentIDLength contains the amount of bytes that a marshaled version of the ContentID contains.
+	ContentIDLength = MessageIDLength
 )
 
 // ContentID identifies the content of a message without its parent1/parent2 ids.
@@ -110,7 +114,7 @@ type Message struct {
 	issuerPublicKey ed25519.PublicKey
 	issuingTime     time.Time
 	sequenceNumber  uint64
-	payload         Payload
+	payload         payload.Payload
 	nonce           uint64
 	signature       ed25519.Signature
 
@@ -124,7 +128,7 @@ type Message struct {
 }
 
 // NewMessage creates a new message with the details provided by the issuer.
-func NewMessage(parent1ID MessageID, parent2ID MessageID, issuingTime time.Time, issuerPublicKey ed25519.PublicKey, sequenceNumber uint64, payload Payload, nonce uint64, signature ed25519.Signature) (result *Message) {
+func NewMessage(parent1ID MessageID, parent2ID MessageID, issuingTime time.Time, issuerPublicKey ed25519.PublicKey, sequenceNumber uint64, payload payload.Payload, nonce uint64, signature ed25519.Signature) (result *Message) {
 	return &Message{
 		parent1ID:       parent1ID,
 		parent2ID:       parent2ID,
@@ -172,7 +176,7 @@ func MessageFromMarshalUtil(marshalUtil *marshalutil.MarshalUtil) (result *Messa
 		err = fmt.Errorf("failed to parse sequence number of the message: %w", err)
 		return
 	}
-	if result.payload, err = PayloadFromMarshalUtil(marshalUtil); err != nil {
+	if result.payload, err = payload.FromMarshalUtil(marshalUtil); err != nil {
 		err = fmt.Errorf("failed to parse payload of the message: %w", err)
 		return
 	}
@@ -282,7 +286,7 @@ func (m *Message) SequenceNumber() uint64 {
 }
 
 // Payload returns the payload of the message.
-func (m *Message) Payload() Payload {
+func (m *Message) Payload() payload.Payload {
 	return m.payload
 }
 
@@ -322,7 +326,7 @@ func (m *Message) ContentID() (result ContentID) {
 // calculates the message id.
 func (m *Message) calculateID() MessageID {
 	return blake2b.Sum512(
-		marshalutil.New(MessageIDLength + MessageIDLength + PayloadIDLength).
+		marshalutil.New(MessageIDLength + MessageIDLength + ContentIDLength).
 			WriteBytes(m.parent1ID.Bytes()).
 			WriteBytes(m.parent2ID.Bytes()).
 			WriteBytes(m.ContentID().Bytes()).
diff --git a/packages/tangle/message_test.go b/packages/tangle/message_test.go
index c7f5e08a88a092c4e105299592d06c2270d501cf..91ce680f36249429012c3e2542490101e7b8609a 100644
--- a/packages/tangle/message_test.go
+++ b/packages/tangle/message_test.go
@@ -4,6 +4,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/crypto/ed25519"
 	"github.com/iotaledger/hive.go/identity"
 	"github.com/iotaledger/hive.go/kvstore/mapdb"
@@ -13,7 +14,7 @@ import (
 
 func TestMessage_VerifySignature(t *testing.T) {
 	keyPair := ed25519.GenerateKeyPair()
-	pl := NewDataPayload([]byte("test"))
+	pl := payload.NewGenericDataPayload([]byte("test"))
 
 	unsigned := NewMessage(EmptyMessageID, EmptyMessageID, time.Time{}, keyPair.PublicKey, 0, pl, 0, ed25519.Signature{})
 	assert.False(t, unsigned.VerifySignature())
@@ -29,7 +30,7 @@ func TestMessage_MarshalUnmarshal(t *testing.T) {
 	msgFactory := NewMessageFactory(mapdb.NewMapDB(), []byte(DBSequenceNumber), identity.GenerateLocalIdentity(), NewMessageTipSelector())
 	defer msgFactory.Shutdown()
 
-	testMessage, err := msgFactory.IssuePayload(NewDataPayload([]byte("test")))
+	testMessage, err := msgFactory.IssuePayload(payload.NewGenericDataPayload([]byte("test")))
 	require.NoError(t, err)
 	assert.Equal(t, true, testMessage.VerifySignature())
 
diff --git a/packages/tangle/messagefactory.go b/packages/tangle/messagefactory.go
index f517dd6e5cf81514d1818b1dcfe1c543009f1217..b2ba17af35f9bfe04cd6c46dc0f867c46ca6b471 100644
--- a/packages/tangle/messagefactory.go
+++ b/packages/tangle/messagefactory.go
@@ -5,6 +5,7 @@ import (
 	"sync"
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/crypto/ed25519"
 	"github.com/iotaledger/hive.go/identity"
 	"github.com/iotaledger/hive.go/kvstore"
@@ -65,10 +66,10 @@ func (f *MessageFactory) SetWorker(worker Worker) {
 // IssuePayload creates a new message including sequence number and tip selection and returns it.
 // It also triggers the MessageConstructed event once it's done, which is for example used by the plugins to listen for
 // messages that shall be attached to the tangle.
-func (f *MessageFactory) IssuePayload(p Payload) (*Message, error) {
+func (f *MessageFactory) IssuePayload(p payload.Payload) (*Message, error) {
 	payloadLen := len(p.Bytes())
-	if payloadLen > MaxPayloadSize {
-		err := fmt.Errorf("%w: %d bytes", ErrMaxPayloadSizeExceeded, payloadLen)
+	if payloadLen > payload.MaxSize {
+		err := fmt.Errorf("maximum payload size of %d bytes exceeded", payloadLen)
 		f.Events.Error.Trigger(err)
 		return nil, err
 	}
@@ -118,7 +119,7 @@ func (f *MessageFactory) Shutdown() {
 	}
 }
 
-func (f *MessageFactory) doPOW(parent1ID MessageID, parent2ID MessageID, issuingTime time.Time, key ed25519.PublicKey, seq uint64, payload Payload) (uint64, error) {
+func (f *MessageFactory) doPOW(parent1ID MessageID, parent2ID MessageID, issuingTime time.Time, key ed25519.PublicKey, seq uint64, payload payload.Payload) (uint64, error) {
 	// create a dummy message to simplify marshaling
 	dummy := NewMessage(parent1ID, parent2ID, issuingTime, key, seq, payload, 0, ed25519.EmptySignature).Bytes()
 
@@ -127,7 +128,7 @@ func (f *MessageFactory) doPOW(parent1ID MessageID, parent2ID MessageID, issuing
 	return f.worker.DoPOW(dummy)
 }
 
-func (f *MessageFactory) sign(parent1ID MessageID, parent2ID MessageID, issuingTime time.Time, key ed25519.PublicKey, seq uint64, payload Payload, nonce uint64) ed25519.Signature {
+func (f *MessageFactory) sign(parent1ID MessageID, parent2ID MessageID, issuingTime time.Time, key ed25519.PublicKey, seq uint64, payload payload.Payload, nonce uint64) ed25519.Signature {
 	// create a dummy message to simplify marshaling
 	dummy := NewMessage(parent1ID, parent2ID, issuingTime, key, seq, payload, nonce, ed25519.EmptySignature)
 	dummyBytes := dummy.Bytes()
diff --git a/packages/tangle/messagefactory_test.go b/packages/tangle/messagefactory_test.go
index 53ac21e84a082377970498c7384b804213214b83..304e0836091255069f2d93b5b03c4a5405be18a4 100644
--- a/packages/tangle/messagefactory_test.go
+++ b/packages/tangle/messagefactory_test.go
@@ -10,6 +10,7 @@ import (
 	"time"
 
 	"github.com/iotaledger/goshimmer/packages/pow"
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/iotaledger/hive.go/identity"
 	"github.com/iotaledger/hive.go/kvstore/mapdb"
@@ -43,7 +44,7 @@ func TestMessageFactory_BuildMessage(t *testing.T) {
 	}))
 
 	t.Run("CheckProperties", func(t *testing.T) {
-		p := NewDataPayload([]byte("TestCheckProperties"))
+		p := payload.NewGenericDataPayload([]byte("TestCheckProperties"))
 		msg, err := msgFactory.IssuePayload(p)
 		require.NoError(t, err)
 
@@ -69,7 +70,7 @@ func TestMessageFactory_BuildMessage(t *testing.T) {
 			t.Run("test", func(t *testing.T) {
 				t.Parallel()
 
-				p := NewDataPayload([]byte("TestParallelCreation"))
+				p := payload.NewGenericDataPayload([]byte("TestParallelCreation"))
 				msg, err := msgFactory.IssuePayload(p)
 				require.NoError(t, err)
 
@@ -126,7 +127,7 @@ func TestMessageFactory_POW(t *testing.T) {
 		return worker.Mine(context.Background(), content, targetPOW)
 	}))
 
-	msg, err := msgFactory.IssuePayload(NewDataPayload([]byte("test")))
+	msg, err := msgFactory.IssuePayload(payload.NewGenericDataPayload([]byte("test")))
 	require.NoError(t, err)
 
 	msgBytes := msg.Bytes()
@@ -148,14 +149,14 @@ func TestWorkerFunc_PayloadSize(t *testing.T) {
 
 	// issue message with max allowed payload size
 	// dataPayload headers: type|32bit + size|32bit
-	data := make([]byte, MaxPayloadSize-4-4)
-	msg, err := msgFactory.IssuePayload(NewDataPayload(data))
+	data := make([]byte, payload.MaxSize-4-4)
+	msg, err := msgFactory.IssuePayload(payload.NewGenericDataPayload(data))
 	require.NoError(t, err)
 	assert.Truef(t, MaxMessageSize == len(msg.Bytes()), "message size should be exactly %d bytes but is %d", MaxMessageSize, len(msg.Bytes()))
 
 	// issue message bigger than max allowed payload size
-	data = make([]byte, MaxPayloadSize)
-	msg, err = msgFactory.IssuePayload(NewDataPayload(data))
+	data = make([]byte, payload.MaxSize)
+	msg, err = msgFactory.IssuePayload(payload.NewGenericDataPayload(data))
 	require.Error(t, err)
 	assert.Nil(t, msg)
 }
diff --git a/packages/tangle/payload.go b/packages/tangle/payload.go
deleted file mode 100644
index beecf71a5ac94dc529cee6b0ed9513184feac2a1..0000000000000000000000000000000000000000
--- a/packages/tangle/payload.go
+++ /dev/null
@@ -1,259 +0,0 @@
-package tangle
-
-import (
-	"fmt"
-	"sync"
-
-	"github.com/iotaledger/hive.go/marshalutil"
-	"github.com/iotaledger/hive.go/stringify"
-	"github.com/mr-tron/base58"
-)
-
-const (
-	// MaxPayloadSize defines the maximum size of a payload.
-	// parent1ID + parent2ID + issuerPublicKey + issuingTime + sequenceNumber + nonce + signature
-	MaxPayloadSize = MaxMessageSize - 64 - 64 - 32 - 8 - 8 - 8 - 64
-
-	// PayloadIDLength is the length of a data payload id.
-	PayloadIDLength = 64
-
-	// ObjectName defines the name of the data object.
-	ObjectName = "data"
-)
-
-var (
-	// ErrMaxPayloadSizeExceeded is returned if the maximum payload size is exceeded.
-	ErrMaxPayloadSizeExceeded = fmt.Errorf("maximum payload size of %d bytes exceeded", MaxPayloadSize)
-
-	typeRegister       = make(map[PayloadType]Definition)
-	typeRegisterMutex  sync.RWMutex
-	genericUnmarshaler Unmarshaler
-)
-
-// PayloadID represents the id of a data payload.
-type PayloadID [PayloadIDLength]byte
-
-// Bytes returns the id as a byte slice backed by the original array,
-// therefore it should not be modified.
-func (id PayloadID) Bytes() []byte {
-	return id[:]
-}
-
-func (id PayloadID) String() string {
-	return base58.Encode(id[:])
-}
-
-// PayloadType represents the type id of a payload.
-type PayloadType = uint32
-
-// Unmarshaler takes some data and unmarshals it into a payload.
-type Unmarshaler func(data []byte) (Payload, error)
-
-// Definition defines the properties of a payload type.
-type Definition struct {
-	Name string
-	Unmarshaler
-}
-
-func init() {
-	// register the generic unmarshaler
-	SetGenericUnmarshaler(GenericPayloadUnmarshaler)
-}
-
-// RegisterPayloadType registers a payload type with the given unmarshaler.
-func RegisterPayloadType(payloadType PayloadType, payloadName string, unmarshaler Unmarshaler) {
-	typeRegisterMutex.Lock()
-	typeRegister[payloadType] = Definition{
-		Name:        payloadName,
-		Unmarshaler: unmarshaler,
-	}
-	typeRegisterMutex.Unlock()
-}
-
-// GetUnmarshaler returns the unmarshaler for the given type if known or
-// the generic unmarshaler if the given payload type has no associated unmarshaler.
-func GetUnmarshaler(payloadType PayloadType) Unmarshaler {
-	typeRegisterMutex.RLock()
-	defer typeRegisterMutex.RUnlock()
-
-	if definition, exists := typeRegister[payloadType]; exists {
-		return definition.Unmarshaler
-	}
-
-	return genericUnmarshaler
-}
-
-// SetGenericUnmarshaler sets the generic unmarshaler.
-func SetGenericUnmarshaler(unmarshaler Unmarshaler) {
-	genericUnmarshaler = unmarshaler
-}
-
-// Name returns the name of a given payload type.
-func Name(payloadType PayloadType) string {
-	typeRegisterMutex.RLock()
-	defer typeRegisterMutex.RUnlock()
-	if definition, exists := typeRegister[payloadType]; exists {
-		return definition.Name
-	}
-	return ObjectName
-}
-
-// Payload represents some kind of payload of data which only gains meaning by having
-// corresponding node logic processing payloads of a given type.
-type Payload interface {
-	// PayloadType returns the type of the payload.
-	Type() PayloadType
-	// Bytes returns the payload bytes.
-	Bytes() []byte
-	// String returns a human-friendly representation of the payload.
-	String() string
-}
-
-// PayloadFromBytes unmarshals bytes into a payload.
-func PayloadFromBytes(bytes []byte) (result Payload, consumedBytes int, err error) {
-	// initialize helper
-	marshalUtil := marshalutil.New(bytes)
-
-	payloadSize, err := marshalUtil.ReadUint32()
-	if err != nil {
-		err = fmt.Errorf("failed to unmarshal payload size from bytes: %w", err)
-		return
-	}
-
-	if payloadSize > MaxPayloadSize {
-		err = fmt.Errorf("%w: %d", ErrMaxPayloadSizeExceeded, payloadSize)
-		return
-	}
-
-	// calculate result
-	payloadType, err := marshalUtil.ReadUint32()
-	if err != nil {
-		err = fmt.Errorf("failed to unmarshal payload type from bytes: %w", err)
-		return
-	}
-
-	marshalUtil.ReadSeek(marshalUtil.ReadOffset() - marshalutil.UINT32_SIZE*2)
-	payloadBytes, err := marshalUtil.ReadBytes(int(payloadSize) + 8)
-	if err != nil {
-		err = fmt.Errorf("failed to unmarshal payload bytes from bytes: %w", err)
-		return
-	}
-
-	readOffset := marshalUtil.ReadOffset()
-	result, err = GetUnmarshaler(payloadType)(payloadBytes)
-	if err != nil {
-		// fallback to the generic unmarshaler if registered type fails to unmarshal
-		marshalUtil.ReadSeek(readOffset)
-		result, err = GenericPayloadUnmarshaler(payloadBytes)
-		if err != nil {
-			err = fmt.Errorf("failed to unmarshal payload from bytes with generic unmarshaler: %w", err)
-			return
-		}
-	}
-
-	// return the number of bytes we processed
-	consumedBytes = marshalUtil.ReadOffset()
-	return
-}
-
-// PayloadFromMarshalUtil parses a payload by using the given marshal util.
-func PayloadFromMarshalUtil(marshalUtil *marshalutil.MarshalUtil) (Payload, error) {
-	payload, err := marshalUtil.Parse(func(data []byte) (interface{}, int, error) { return PayloadFromBytes(data) })
-	if err != nil {
-		err = fmt.Errorf("failed to parse payload: %w", err)
-		return nil, err
-	}
-	return payload.(Payload), nil
-}
-
-// DataType is the message type of a data payload.
-var DataType = PayloadType(0)
-
-func init() {
-	// register the generic data payload type
-	RegisterPayloadType(DataType, ObjectName, GenericPayloadUnmarshaler)
-}
-
-// DataPayload represents a payload which just contains a blob of data.
-type DataPayload struct {
-	payloadType PayloadType
-	data        []byte
-}
-
-// NewDataPayload creates new data payload.
-func NewDataPayload(data []byte) *DataPayload {
-	return &DataPayload{
-		payloadType: DataType,
-		data:        data,
-	}
-}
-
-// DataPayloadFromBytes creates a new data payload from the given bytes.
-func DataPayloadFromBytes(bytes []byte) (result *DataPayload, consumedBytes int, err error) {
-	marshalUtil := marshalutil.New(bytes)
-	result, err = DataPayloadFromMarshalUtil(marshalUtil)
-	consumedBytes = marshalUtil.ReadOffset()
-
-	return
-}
-
-// DataPayloadFromMarshalUtil parses a new data payload out of the given marshal util.
-func DataPayloadFromMarshalUtil(marshalUtil *marshalutil.MarshalUtil) (result *DataPayload, err error) {
-	// parse information
-	result = &DataPayload{}
-	payloadBytes, err := marshalUtil.ReadUint32()
-	if err != nil {
-		err = fmt.Errorf("failed to parse data payload size: %w", err)
-		return
-	}
-	result.payloadType, err = marshalUtil.ReadUint32()
-	if err != nil {
-		err = fmt.Errorf("failed to parse data payload type: %w", err)
-		return
-	}
-	result.data, err = marshalUtil.ReadBytes(int(payloadBytes))
-	if err != nil {
-		err = fmt.Errorf("failed to parse data payload contest: %w", err)
-		return
-	}
-
-	return
-}
-
-// Type returns the payload type.
-func (d *DataPayload) Type() PayloadType {
-	return d.payloadType
-}
-
-// Data returns the data of the data payload.
-func (d *DataPayload) Data() []byte {
-	return d.data
-}
-
-// Bytes marshals the data payload into a sequence of bytes.
-func (d *DataPayload) Bytes() []byte {
-	// initialize helper
-	marshalUtil := marshalutil.New()
-
-	// marshal the payload specific information
-	marshalUtil.WriteUint32(uint32(len(d.data)))
-	marshalUtil.WriteUint32(d.Type())
-	marshalUtil.WriteBytes(d.data[:])
-
-	// return result
-	return marshalUtil.Bytes()
-}
-
-func (d *DataPayload) String() string {
-	return stringify.Struct("Data",
-		stringify.StructField("type", int(d.Type())),
-		stringify.StructField("data", string(d.Data())),
-	)
-}
-
-// GenericPayloadUnmarshaler is an unmarshaler for the generic data payload type.
-func GenericPayloadUnmarshaler(data []byte) (payload Payload, err error) {
-	payload, _, err = DataPayloadFromBytes(data)
-
-	return
-}
diff --git a/packages/tangle/payload/data.go b/packages/tangle/payload/data.go
new file mode 100644
index 0000000000000000000000000000000000000000..a34c3bac7c845fd694445c367b683c7f09dce3f5
--- /dev/null
+++ b/packages/tangle/payload/data.go
@@ -0,0 +1,89 @@
+package payload
+
+import (
+	"github.com/iotaledger/hive.go/marshalutil"
+	"github.com/iotaledger/hive.go/stringify"
+	"golang.org/x/xerrors"
+)
+
+// GenericDataPayloadType is the Type of a generic GenericDataPayload.
+var GenericDataPayloadType = NewType(0, "GenericDataPayloadType", GenericDataPayloadUnmarshaler)
+
+// GenericDataPayloadUnmarshaler is the UnmarshalerFunc of the GenericDataPayload which is also used as a unmarshaler for unknown Types.
+func GenericDataPayloadUnmarshaler(data []byte) (Payload, error) {
+	return GenericDataPayloadFromMarshalUtil(marshalutil.New(data))
+}
+
+// GenericDataPayload represents a payload which just contains a blob of data.
+type GenericDataPayload struct {
+	payloadType Type
+	data        []byte
+}
+
+// NewGenericDataPayload creates new GenericDataPayload.
+func NewGenericDataPayload(data []byte) *GenericDataPayload {
+	return &GenericDataPayload{
+		payloadType: GenericDataPayloadType,
+		data:        data,
+	}
+}
+
+// GenericDataPayloadFromBytes unmarshals a GenericDataPayload from a sequence of bytes.
+func GenericDataPayloadFromBytes(bytes []byte) (genericDataPayload *GenericDataPayload, consumedBytes int, err error) {
+	marshalUtil := marshalutil.New(bytes)
+	if genericDataPayload, err = GenericDataPayloadFromMarshalUtil(marshalUtil); err != nil {
+		err = xerrors.Errorf("failed to parse GenericDataPayload from MarshalUtil: %w", err)
+		return
+	}
+	consumedBytes = marshalUtil.ReadOffset()
+
+	return
+}
+
+// GenericDataPayloadFromMarshalUtil unmarshals a GenericDataPayload using a MarshalUtil (for easier unmarshaling).
+func GenericDataPayloadFromMarshalUtil(marshalUtil *marshalutil.MarshalUtil) (genericDataPayload *GenericDataPayload, err error) {
+	payloadSize, err := marshalUtil.ReadUint32()
+	if err != nil {
+		err = xerrors.Errorf("failed to parse payload size (%v): %w", err, ErrParseBytesFailed)
+		return
+	}
+
+	genericDataPayload = &GenericDataPayload{}
+	if genericDataPayload.payloadType, err = TypeFromMarshalUtil(marshalUtil); err != nil {
+		err = xerrors.Errorf("failed to parse Type from MarshalUtil: %w", err)
+		return
+	}
+	if genericDataPayload.data, err = marshalUtil.ReadBytes(int(payloadSize)); err != nil {
+		err = xerrors.Errorf("failed to parse data (%v): %w", err, ErrParseBytesFailed)
+		return
+	}
+
+	return
+}
+
+// Type returns the Type of the Payload.
+func (g *GenericDataPayload) Type() Type {
+	return g.payloadType
+}
+
+// Blob returns the contained data of the GenericDataPayload (without its type and size headers).
+func (g *GenericDataPayload) Blob() []byte {
+	return g.data
+}
+
+// Bytes returns a marshaled version of the Payload.
+func (g *GenericDataPayload) Bytes() []byte {
+	return marshalutil.New().
+		WriteUint32(uint32(len(g.data))).
+		WriteBytes(g.Type().Bytes()).
+		WriteBytes(g.Blob()).
+		Bytes()
+}
+
+// String returns a human readable version of the Payload.
+func (g *GenericDataPayload) String() string {
+	return stringify.Struct("GenericDataPayload",
+		stringify.StructField("type", g.Type()),
+		stringify.StructField("blob", g.Blob()),
+	)
+}
diff --git a/packages/tangle/payload/errors.go b/packages/tangle/payload/errors.go
new file mode 100644
index 0000000000000000000000000000000000000000..b587ba959924892243062032a718105585dd7d7a
--- /dev/null
+++ b/packages/tangle/payload/errors.go
@@ -0,0 +1,10 @@
+package payload
+
+import (
+	"errors"
+)
+
+var (
+	// ErrParseBytesFailed is returned if information can not be parsed from a sequence of bytes.
+	ErrParseBytesFailed = errors.New("failed to parse bytes")
+)
diff --git a/packages/tangle/payload/payload.go b/packages/tangle/payload/payload.go
new file mode 100644
index 0000000000000000000000000000000000000000..9868e7e9a8d18893aff0bc082c45d1e7c039e849
--- /dev/null
+++ b/packages/tangle/payload/payload.go
@@ -0,0 +1,73 @@
+package payload
+
+import (
+	"fmt"
+
+	"github.com/iotaledger/hive.go/marshalutil"
+	"golang.org/x/xerrors"
+)
+
+// MaxSize defines the maximum allowed size of a marshaled Payload (in bytes).
+const MaxSize = 65288
+
+// Payload represents the generic interface for an object that can be embedded in Messages of the Tangle.
+type Payload interface {
+	// Type returns the Type of the Payload.
+	Type() Type
+
+	// Bytes returns a marshaled version of the Payload.
+	Bytes() []byte
+
+	// String returns a human readable version of the Payload.
+	String() string
+}
+
+// FromBytes unmarshals a Payload from a sequence of bytes.
+func FromBytes(payloadBytes []byte) (payload Payload, consumedBytes int, err error) {
+	marshalUtil := marshalutil.New(payloadBytes)
+	if payload, err = FromMarshalUtil(marshalUtil); err != nil {
+		err = xerrors.Errorf("failed to parse Payload from MarshalUtil: %w", err)
+		return
+	}
+	consumedBytes = marshalUtil.ReadOffset()
+
+	return
+}
+
+// FromMarshalUtil unmarshals a Payload using a MarshalUtil (for easier unmarshaling).
+func FromMarshalUtil(marshalUtil *marshalutil.MarshalUtil) (payload Payload, err error) {
+	payloadSize, err := marshalUtil.ReadUint32()
+	if err != nil {
+		err = xerrors.Errorf("failed to parse payload size (%v): %w", err, ErrParseBytesFailed)
+		return
+	}
+	if payloadSize > MaxSize {
+		err = xerrors.Errorf("maximum payload size of %d bytes exceeded: %w", MaxSize, ErrParseBytesFailed)
+		return
+	}
+
+	payloadType, err := TypeFromMarshalUtil(marshalUtil)
+	if err != nil {
+		err = xerrors.Errorf("failed to unmarshal Type from MarshalUtil: %w", err)
+		return
+	}
+
+	marshalUtil.ReadSeek(-marshalutil.UINT32_SIZE * 2)
+	payloadBytes, err := marshalUtil.ReadBytes(int(payloadSize) + 8)
+	if err != nil {
+		err = xerrors.Errorf("failed to unmarshal payload bytes (%v): %w", err, ErrParseBytesFailed)
+		return
+	}
+
+	readOffset := marshalUtil.ReadOffset()
+	if payload, err = Unmarshaler(payloadType)(payloadBytes); err != nil {
+		marshalUtil.ReadSeek(readOffset)
+
+		if payload, err = GenericDataPayloadUnmarshaler(payloadBytes); err != nil {
+			err = fmt.Errorf("failed to parse Payload with generic GenericDataPayloadUnmarshaler: %w", err)
+			return
+		}
+	}
+
+	return
+}
diff --git a/packages/tangle/payload/type.go b/packages/tangle/payload/type.go
new file mode 100644
index 0000000000000000000000000000000000000000..db776ad5f056d3c1bde7be4fdc33baaa8a2db265
--- /dev/null
+++ b/packages/tangle/payload/type.go
@@ -0,0 +1,93 @@
+package payload
+
+import (
+	"encoding/binary"
+	"strconv"
+	"sync"
+
+	"github.com/iotaledger/hive.go/marshalutil"
+	"golang.org/x/xerrors"
+)
+
+// Type represents the Type of a payload.
+type Type uint32
+
+// typeMetadata holds additional information for registered Types.
+type typeMetadata struct {
+	Name string
+	UnmarshalerFunc
+}
+
+var (
+	// typeRegister contains a map of all Types that where registered by the node.
+	typeRegister = make(map[Type]typeMetadata)
+
+	// typeRegisterMutex is used to make synchronize the access to the previously defined map.
+	typeRegisterMutex sync.RWMutex
+)
+
+// NewType creates and registers a new payload Type.
+func NewType(typeNumber uint32, typeName string, typeUnmarshaler UnmarshalerFunc) (payloadType Type) {
+	payloadType = Type(typeNumber)
+
+	typeRegisterMutex.Lock()
+	defer typeRegisterMutex.Unlock()
+
+	if registeredType, typeRegisteredAlready := typeRegister[payloadType]; typeRegisteredAlready {
+		panic("payload type " +
+			typeName + "(" + strconv.FormatUint(uint64(typeNumber), 10) + ")" +
+			" tries to overwrite previously created type " +
+			registeredType.Name + "(" + strconv.FormatUint(uint64(typeNumber), 10) + ")")
+	}
+
+	typeRegister[payloadType] = typeMetadata{
+		Name:            typeName,
+		UnmarshalerFunc: typeUnmarshaler,
+	}
+
+	return
+}
+
+// TypeFromBytes unmarshals a Type from a sequence of bytes.
+func TypeFromBytes(typeBytes []byte) (typeResult Type, consumedBytes int, err error) {
+	marshalUtil := marshalutil.New(typeBytes)
+	if typeResult, err = TypeFromMarshalUtil(marshalUtil); err != nil {
+		err = xerrors.Errorf("failed to parse Type from MarshalUtil: %w", err)
+		return
+	}
+	consumedBytes = marshalUtil.ReadOffset()
+
+	return
+}
+
+// TypeFromMarshalUtil unmarshals a Type using a MarshalUtil (for easier unmarshaling).
+func TypeFromMarshalUtil(marshalUtil *marshalutil.MarshalUtil) (typeResult Type, err error) {
+	typeUint32, err := marshalUtil.ReadUint32()
+	if err != nil {
+		err = xerrors.Errorf("failed to parse type (%v): %w", err, ErrParseBytesFailed)
+		return
+	}
+	typeResult = Type(typeUint32)
+
+	return
+}
+
+// Bytes returns a marshaled version of the Type.
+func (t Type) Bytes() (bytes []byte) {
+	bytes = make([]byte, 4)
+	binary.LittleEndian.PutUint32(bytes, uint32(t))
+
+	return
+}
+
+// String returns a human readable version of the Type for debug purposes.
+func (t Type) String() string {
+	typeRegisterMutex.RLock()
+	defer typeRegisterMutex.RUnlock()
+
+	if definition, exists := typeRegister[t]; exists {
+		return definition.Name + "(" + strconv.FormatUint(uint64(t), 10) + ")"
+	}
+
+	return "UnknownType(" + strconv.FormatUint(uint64(t), 10) + ")"
+}
diff --git a/packages/tangle/payload/unmarshaler.go b/packages/tangle/payload/unmarshaler.go
new file mode 100644
index 0000000000000000000000000000000000000000..d340dcc1969ee956aaa12da57312d6ad7e5d3af8
--- /dev/null
+++ b/packages/tangle/payload/unmarshaler.go
@@ -0,0 +1,16 @@
+package payload
+
+// UnmarshalerFunc defines the function signature for functions that can unmarshal Payloads.
+type UnmarshalerFunc func(data []byte) (Payload, error)
+
+// Unmarshaler returns the UnmarshalerFunc for the given Type or the GenericDataPayloadUnmarshaler if the Type is unknown.
+func Unmarshaler(payloadType Type) UnmarshalerFunc {
+	typeRegisterMutex.RLock()
+	defer typeRegisterMutex.RUnlock()
+
+	if definition, exists := typeRegister[payloadType]; exists {
+		return definition.UnmarshalerFunc
+	}
+
+	return GenericDataPayloadUnmarshaler
+}
diff --git a/packages/tangle/payload_test.go b/packages/tangle/payload_test.go
index 92512835a58ca46d87335b11896a8eeefa1b2631..28e78ce2b1bbaefe74b9e47a1dbd46fe6602ac1e 100644
--- a/packages/tangle/payload_test.go
+++ b/packages/tangle/payload_test.go
@@ -5,6 +5,7 @@ import (
 	"sync"
 	"testing"
 
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/async"
 	"github.com/iotaledger/hive.go/identity"
 	"github.com/iotaledger/hive.go/kvstore/mapdb"
@@ -21,7 +22,7 @@ func BenchmarkVerifyDataMessages(b *testing.B) {
 
 	messages := make([][]byte, b.N)
 	for i := 0; i < b.N; i++ {
-		msg, err := factory.IssuePayload(NewDataPayload([]byte("some data")))
+		msg, err := factory.IssuePayload(payload.NewGenericDataPayload([]byte("some data")))
 		require.NoError(b, err)
 		messages[i] = msg.Bytes()
 	}
@@ -49,7 +50,7 @@ func BenchmarkVerifySignature(b *testing.B) {
 
 	messages := make([]*Message, b.N)
 	for i := 0; i < b.N; i++ {
-		msg, err := factory.IssuePayload(NewDataPayload([]byte("some data")))
+		msg, err := factory.IssuePayload(payload.NewGenericDataPayload([]byte("some data")))
 		require.NoError(b, err)
 		messages[i] = msg
 		messages[i].Bytes()
diff --git a/packages/tangle/tangle_test.go b/packages/tangle/tangle_test.go
index 2407814aa18083e5b1f7c006ba4c83ac46c7e107..c8d5d3771dace96a29486693026d1116640cdc38 100644
--- a/packages/tangle/tangle_test.go
+++ b/packages/tangle/tangle_test.go
@@ -8,6 +8,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/datastructure/randommap"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/iotaledger/hive.go/identity"
@@ -120,7 +121,7 @@ func TestTangle_MissingMessages(t *testing.T) {
 	// create a helper function that creates the messages
 	createNewMessage := func() *Message {
 		// issue the payload
-		msg, err := msgFactory.IssuePayload(NewDataPayload([]byte("0")))
+		msg, err := msgFactory.IssuePayload(payload.NewGenericDataPayload([]byte("0")))
 		require.NoError(t, err)
 
 		// remove a tip if the width of the tangle is reached
diff --git a/packages/tangle/test_utils.go b/packages/tangle/test_utils.go
index df737ae8873adbdc1a7bb10fbac4342e99a14e90..e0808bbe602871d2d1348589f45be4f4834a1011 100644
--- a/packages/tangle/test_utils.go
+++ b/packages/tangle/test_utils.go
@@ -3,17 +3,18 @@ package tangle
 import (
 	"time"
 
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/crypto/ed25519"
 )
 
 func newTestNonceMessage(nonce uint64) *Message {
-	return NewMessage(EmptyMessageID, EmptyMessageID, time.Time{}, ed25519.PublicKey{}, 0, NewDataPayload([]byte("test")), nonce, ed25519.Signature{})
+	return NewMessage(EmptyMessageID, EmptyMessageID, time.Time{}, ed25519.PublicKey{}, 0, payload.NewGenericDataPayload([]byte("test")), nonce, ed25519.Signature{})
 }
 
 func newTestDataMessage(payloadString string) *Message {
-	return NewMessage(EmptyMessageID, EmptyMessageID, time.Now(), ed25519.PublicKey{}, 0, NewDataPayload([]byte(payloadString)), 0, ed25519.Signature{})
+	return NewMessage(EmptyMessageID, EmptyMessageID, time.Now(), ed25519.PublicKey{}, 0, payload.NewGenericDataPayload([]byte(payloadString)), 0, ed25519.Signature{})
 }
 
 func newTestParentsDataMessage(payloadString string, parent1, parent2 MessageID) *Message {
-	return NewMessage(parent1, parent2, time.Now(), ed25519.PublicKey{}, 0, NewDataPayload([]byte(payloadString)), 0, ed25519.Signature{})
+	return NewMessage(parent1, parent2, time.Now(), ed25519.PublicKey{}, 0, payload.NewGenericDataPayload([]byte(payloadString)), 0, ed25519.Signature{})
 }
diff --git a/plugins/dashboard/explorer_routes.go b/plugins/dashboard/explorer_routes.go
index f1c84bfe8ffb0054803da20b8fed5a99a1a02800..d6a1b898554c7f71c3b0fb5cbb6b18727d1ff324 100644
--- a/plugins/dashboard/explorer_routes.go
+++ b/plugins/dashboard/explorer_routes.go
@@ -55,7 +55,7 @@ func createExplorerMessage(msg *tangle.Message) (*ExplorerMessage, error) {
 		Parent1MessageID:        msg.Parent1ID().String(),
 		Parent2MessageID:        msg.Parent2ID().String(),
 		Solid:                   cachedMessageMetadata.Unwrap().IsSolid(),
-		PayloadType:             msg.Payload().Type(),
+		PayloadType:             uint32(msg.Payload().Type()),
 		Payload:                 ProcessPayload(msg.Payload()),
 	}
 
diff --git a/plugins/dashboard/payload_handler.go b/plugins/dashboard/payload_handler.go
index 797877395568552b607e68bde26f117d8d8dc516..049792c434871c96a5080c711fed8731d645ee96 100644
--- a/plugins/dashboard/payload_handler.go
+++ b/plugins/dashboard/payload_handler.go
@@ -6,7 +6,7 @@ import (
 	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/balance"
 	valuepayload "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/payload"
 	"github.com/iotaledger/goshimmer/packages/drng"
-	"github.com/iotaledger/goshimmer/packages/tangle"
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	syncbeaconpayload "github.com/iotaledger/goshimmer/plugins/syncbeacon/payload"
 	"github.com/iotaledger/hive.go/marshalutil"
 )
@@ -75,13 +75,13 @@ type Balance struct {
 
 // ProcessPayload returns different structs regarding to the
 // payload type.
-func ProcessPayload(p tangle.Payload) interface{} {
+func ProcessPayload(p payload.Payload) interface{} {
 	switch p.Type() {
-	case tangle.DataType:
+	case payload.GenericDataPayloadType:
 		// data payload
 		return BasicPayload{
-			ContentTitle: "Data",
-			Content:      p.(*tangle.DataPayload).Data(),
+			ContentTitle: "GenericDataPayload",
+			Content:      p.(*payload.GenericDataPayload).Blob(),
 		}
 	case faucetpayload.Type:
 		// faucet payload
@@ -107,7 +107,7 @@ func ProcessPayload(p tangle.Payload) interface{} {
 }
 
 // processDrngPayload handles the subtypes of Drng payload
-func processDrngPayload(p tangle.Payload) (dp DrngPayload) {
+func processDrngPayload(p payload.Payload) (dp DrngPayload) {
 	var subpayload interface{}
 	marshalUtil := marshalutil.New(p.Bytes())
 	drngPayload, _ := drng.PayloadFromMarshalUtil(marshalUtil)
@@ -137,7 +137,7 @@ func processDrngPayload(p tangle.Payload) (dp DrngPayload) {
 }
 
 // processDrngPayload handles the subtypes of Drng payload
-func processSyncBeaconPayload(p tangle.Payload) (dp SyncBeaconPayload) {
+func processSyncBeaconPayload(p payload.Payload) (dp SyncBeaconPayload) {
 	syncBeaconPayload, ok := p.(*syncbeaconpayload.Payload)
 	if !ok {
 		log.Info("could not cast payload to sync beacon object")
@@ -150,7 +150,7 @@ func processSyncBeaconPayload(p tangle.Payload) (dp SyncBeaconPayload) {
 }
 
 // processValuePayload handles Value payload
-func processValuePayload(p tangle.Payload) (vp ValuePayload) {
+func processValuePayload(p payload.Payload) (vp ValuePayload) {
 	marshalUtil := marshalutil.New(p.Bytes())
 	v, _ := valuepayload.Parse(marshalUtil)
 
diff --git a/plugins/issuer/plugin.go b/plugins/issuer/plugin.go
index 2d75f13ba9551d1278f0d202da7cbed85d30712b..253eecf62f3984918b5768028ccc54c39e13b895 100644
--- a/plugins/issuer/plugin.go
+++ b/plugins/issuer/plugin.go
@@ -5,6 +5,7 @@ import (
 	goSync "sync"
 
 	"github.com/iotaledger/goshimmer/packages/tangle"
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/goshimmer/plugins/messagelayer"
 	"github.com/iotaledger/goshimmer/plugins/syncbeaconfollower"
 	"github.com/iotaledger/hive.go/node"
@@ -31,7 +32,7 @@ func configure(_ *node.Plugin) {}
 
 // IssuePayload issues a payload to the message layer.
 // If the node is not synchronized an error is returned.
-func IssuePayload(payload tangle.Payload) (*tangle.Message, error) {
+func IssuePayload(payload payload.Payload) (*tangle.Message, error) {
 	if !syncbeaconfollower.Synced() {
 		return nil, fmt.Errorf("can't issue payload: %w", syncbeaconfollower.ErrNodeNotSynchronized)
 	}
diff --git a/plugins/metrics/message.go b/plugins/metrics/message.go
index c32fc9cf4db2ba0bdea93ad59166d92ee9c7e2cb..3476673ed951335d42048d584cc90014aad4add9 100644
--- a/plugins/metrics/message.go
+++ b/plugins/metrics/message.go
@@ -4,7 +4,7 @@ import (
 	"time"
 
 	"github.com/iotaledger/goshimmer/packages/metrics"
-	"github.com/iotaledger/goshimmer/packages/tangle"
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/goshimmer/plugins/messagelayer"
 	"github.com/iotaledger/hive.go/syncutils"
 	"go.uber.org/atomic"
@@ -49,7 +49,7 @@ var (
 	measuredReceivedMPS atomic.Uint64
 
 	// Number of messages per payload type since start of the node.
-	messageCountPerPayload = make(map[tangle.PayloadType]uint64)
+	messageCountPerPayload = make(map[payload.Type]uint64)
 
 	// protect map from concurrent read/write.
 	messageCountPerPayloadMutex syncutils.RWMutex
@@ -66,17 +66,17 @@ func MessageTotalCountSinceStart() uint64 {
 }
 
 // MessageCountSinceStartPerPayload returns a map of message payload types and their count since the start of the node.
-func MessageCountSinceStartPerPayload() map[tangle.PayloadType]uint64 {
+func MessageCountSinceStartPerPayload() map[payload.Type]uint64 {
 	messageCountPerPayloadMutex.RLock()
 	defer messageCountPerPayloadMutex.RUnlock()
 
 	// copy the original map
-	copy := make(map[tangle.PayloadType]uint64)
+	clone := make(map[payload.Type]uint64)
 	for key, element := range messageCountPerPayload {
-		copy[key] = element
+		clone[key] = element
 	}
 
-	return copy
+	return clone
 }
 
 // MessageTips returns the actual number of tips in the message tangle.
@@ -122,7 +122,7 @@ func ReceivedMessagesPerSecond() uint64 {
 
 ////// Handling data updates and measuring //////
 
-func increasePerPayloadCounter(p tangle.PayloadType) {
+func increasePerPayloadCounter(p payload.Type) {
 	messageCountPerPayloadMutex.Lock()
 	defer messageCountPerPayloadMutex.Unlock()
 
diff --git a/plugins/metrics/message_test.go b/plugins/metrics/message_test.go
index cdab7406b86051c7dc9fb24bcd42212dbb095f43..bd8ae636cb22a015ccddfa60793f9e114f3189a3 100644
--- a/plugins/metrics/message_test.go
+++ b/plugins/metrics/message_test.go
@@ -7,7 +7,7 @@ import (
 	valuepayload "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/payload"
 	"github.com/iotaledger/goshimmer/packages/drng"
 	"github.com/iotaledger/goshimmer/packages/metrics"
-	"github.com/iotaledger/goshimmer/packages/tangle"
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/goshimmer/plugins/messagelayer"
 	"github.com/iotaledger/hive.go/events"
 	"github.com/magiconair/properties/assert"
@@ -21,13 +21,13 @@ func TestMessageCountPerPayload(t *testing.T) {
 		increasePerPayloadCounter(valuepayload.Type)
 	}
 	assert.Equal(t, MessageTotalCountSinceStart(), (uint64)(10))
-	assert.Equal(t, MessageCountSinceStartPerPayload(), map[tangle.PayloadType]uint64{valuepayload.Type: 10})
+	assert.Equal(t, MessageCountSinceStartPerPayload(), map[payload.Type]uint64{valuepayload.Type: 10})
 	// simulate attaching 5 drng payloads
 	for i := 0; i < 5; i++ {
 		increasePerPayloadCounter(drng.PayloadType)
 	}
 	assert.Equal(t, MessageTotalCountSinceStart(), (uint64)(15))
-	assert.Equal(t, MessageCountSinceStartPerPayload(), map[tangle.PayloadType]uint64{valuepayload.Type: 10, drng.PayloadType: 5})
+	assert.Equal(t, MessageCountSinceStartPerPayload(), map[payload.Type]uint64{valuepayload.Type: 10, drng.PayloadType: 5})
 }
 
 func TestMessageTips(t *testing.T) {
diff --git a/plugins/networkdelay/object.go b/plugins/networkdelay/object.go
index a331e4b12cfe62122bc82e65501755f860058898..951d72e60993705c4b3c462c68a2621a34cac722 100644
--- a/plugins/networkdelay/object.go
+++ b/plugins/networkdelay/object.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"sync"
 
-	"github.com/iotaledger/goshimmer/packages/tangle"
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/stringify"
 	"github.com/mr-tron/base58"
@@ -111,7 +111,7 @@ func (o *Object) Bytes() (bytes []byte) {
 
 	// marshal the payload specific information
 	marshalUtil.WriteUint32(uint32(objectLength))
-	marshalUtil.WriteUint32(Type)
+	marshalUtil.WriteBytes(Type.Bytes())
 	marshalUtil.WriteBytes(o.id[:])
 	marshalUtil.WriteInt64(o.sentTime)
 
@@ -131,19 +131,15 @@ func (o *Object) String() string {
 // region Payload implementation ///////////////////////////////////////////////////////////////////////////////////////
 
 // Type represents the identifier which addresses the network delay Object type.
-const Type = tangle.PayloadType(189)
+var Type = payload.NewType(189, ObjectName, func(data []byte) (payload payload.Payload, err error) {
+	payload, _, err = FromBytes(data)
+
+	return
+})
 
 // Type returns the type of the Object.
-func (o *Object) Type() tangle.PayloadType {
+func (o *Object) Type() payload.Type {
 	return Type
 }
 
-func init() {
-	tangle.RegisterPayloadType(Type, ObjectName, func(data []byte) (payload tangle.Payload, err error) {
-		payload, _, err = FromBytes(data)
-
-		return
-	})
-}
-
 // // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/prometheus/tangle.go b/plugins/prometheus/tangle.go
index da20c98aa63dbd63bc004c4832e63c3230d66fd8..684e6098ef40497895ff5e24a34185196a8f7de3 100644
--- a/plugins/prometheus/tangle.go
+++ b/plugins/prometheus/tangle.go
@@ -1,7 +1,6 @@
 package prometheus
 
 import (
-	"github.com/iotaledger/goshimmer/packages/tangle"
 	"github.com/iotaledger/goshimmer/plugins/metrics"
 	"github.com/prometheus/client_golang/prometheus"
 )
@@ -92,7 +91,7 @@ func collectTangleMetrics() {
 	messageTips.Set(float64(metrics.MessageTips()))
 	msgCountPerPayload := metrics.MessageCountSinceStartPerPayload()
 	for payloadType, count := range msgCountPerPayload {
-		messagePerTypeCount.WithLabelValues(tangle.Name(payloadType)).Set(float64(count))
+		messagePerTypeCount.WithLabelValues(payloadType.String()).Set(float64(count))
 	}
 	messageTotalCount.Set(float64(metrics.MessageTotalCountSinceStart()))
 	messageTotalCountDB.Set(float64(metrics.MessageTotalCountDB()))
diff --git a/plugins/syncbeacon/payload/payload.go b/plugins/syncbeacon/payload/payload.go
index 59f4d547ae1cda174998a9fef5a11e0e4e1d9485..18fcbb38a2d39ce3da89551527f158c53a479cd0 100644
--- a/plugins/syncbeacon/payload/payload.go
+++ b/plugins/syncbeacon/payload/payload.go
@@ -3,7 +3,7 @@ package payload
 import (
 	"fmt"
 
-	"github.com/iotaledger/goshimmer/packages/tangle"
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 
 	"github.com/iotaledger/hive.go/marshalutil"
 	"github.com/iotaledger/hive.go/stringify"
@@ -15,11 +15,15 @@ const (
 )
 
 // Type is the type of the syncbeacon payload.
-var Type = tangle.PayloadType(200)
+var Type = payload.NewType(200, ObjectName, func(data []byte) (payload payload.Payload, err error) {
+	payload, _, err = FromBytes(data)
+
+	return
+})
 
 // Payload represents the syncbeacon payload
 type Payload struct {
-	payloadType tangle.PayloadType
+	payloadType payload.Type
 	sentTime    int64
 }
 
@@ -44,7 +48,7 @@ func FromBytes(bytes []byte) (result *Payload, consumedBytes int, err error) {
 		err = fmt.Errorf("failed to parse payload size of syncbeacon payload: %w", err)
 		return
 	}
-	result.payloadType, err = marshalUtil.ReadUint32()
+	result.payloadType, err = payload.TypeFromMarshalUtil(marshalUtil)
 	if err != nil {
 		err = fmt.Errorf("failed to parse payload type of syncbeacon payload: %w", err)
 		return
@@ -62,7 +66,7 @@ func FromBytes(bytes []byte) (result *Payload, consumedBytes int, err error) {
 }
 
 // Type returns the type of the Payload.
-func (p *Payload) Type() tangle.PayloadType {
+func (p *Payload) Type() payload.Type {
 	return p.payloadType
 }
 
@@ -79,7 +83,7 @@ func (p *Payload) Bytes() []byte {
 
 	// marshal the p specific information
 	marshalUtil.WriteUint32(uint32(objectLength))
-	marshalUtil.WriteUint32(Type)
+	marshalUtil.WriteBytes(Type.Bytes())
 	marshalUtil.WriteInt64(p.sentTime)
 
 	// return result
@@ -96,11 +100,3 @@ func (p *Payload) String() string {
 func IsSyncBeaconPayload(p *Payload) bool {
 	return p.Type() == Type
 }
-
-func init() {
-	tangle.RegisterPayloadType(Type, ObjectName, func(data []byte) (payload tangle.Payload, err error) {
-		payload, _, err = FromBytes(data)
-
-		return
-	})
-}
diff --git a/plugins/webapi/data/plugin.go b/plugins/webapi/data/plugin.go
index 96a31141d4649223157ea369bd908ff88034a03a..445296e0b770e8f432b153a5dbeff99dffc68ea6 100644
--- a/plugins/webapi/data/plugin.go
+++ b/plugins/webapi/data/plugin.go
@@ -4,7 +4,7 @@ import (
 	"net/http"
 	"sync"
 
-	"github.com/iotaledger/goshimmer/packages/tangle"
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/goshimmer/plugins/issuer"
 	"github.com/iotaledger/goshimmer/plugins/webapi"
 	"github.com/iotaledger/hive.go/logger"
@@ -44,7 +44,7 @@ func broadcastData(c echo.Context) error {
 		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
 	}
 
-	msg, err := issuer.IssuePayload(tangle.NewDataPayload(request.Data))
+	msg, err := issuer.IssuePayload(payload.NewGenericDataPayload(request.Data))
 	if err != nil {
 		return c.JSON(http.StatusBadRequest, Response{Error: err.Error()})
 	}
diff --git a/plugins/webapi/message/sendPayload.go b/plugins/webapi/message/sendPayload.go
index 61115bead14ab8fa37919308bab12ab1edfd3bad..725a0353a1ba82746099c8833939c4e36e6f731c 100644
--- a/plugins/webapi/message/sendPayload.go
+++ b/plugins/webapi/message/sendPayload.go
@@ -3,7 +3,7 @@ package message
 import (
 	"net/http"
 
-	"github.com/iotaledger/goshimmer/packages/tangle"
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	"github.com/iotaledger/goshimmer/plugins/issuer"
 	"github.com/labstack/echo"
 )
@@ -17,7 +17,7 @@ func sendPayloadHandler(c echo.Context) error {
 		return c.JSON(http.StatusBadRequest, SendPayloadResponse{Error: err.Error()})
 	}
 
-	parsedPayload, _, err := tangle.PayloadFromBytes(request.Payload)
+	parsedPayload, _, err := payload.FromBytes(request.Payload)
 	if err != nil {
 		return c.JSON(http.StatusBadRequest, SendPayloadResponse{Error: err.Error()})
 	}
diff --git a/tools/integration-tests/tester/tests/testutil.go b/tools/integration-tests/tester/tests/testutil.go
index 3f8b586e5db902d63efe08cc4f594f7308abff81..328ee9d699726fe0bfd74e4b5f47057e09752073 100644
--- a/tools/integration-tests/tester/tests/testutil.go
+++ b/tools/integration-tests/tester/tests/testutil.go
@@ -13,7 +13,7 @@ import (
 	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address/signaturescheme"
 	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/balance"
 	"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction"
-	"github.com/iotaledger/goshimmer/packages/tangle"
+	"github.com/iotaledger/goshimmer/packages/tangle/payload"
 	valueutils "github.com/iotaledger/goshimmer/plugins/webapi/value"
 	"github.com/iotaledger/goshimmer/tools/integration-tests/tester/framework"
 	"github.com/iotaledger/hive.go/types"
@@ -70,7 +70,7 @@ func SendDataMessage(t *testing.T, peer *framework.Peer, data []byte, number int
 		number: number,
 		id:     id,
 		// save payload to be able to compare API response
-		data:            tangle.NewDataPayload(data).Bytes(),
+		data:            payload.NewGenericDataPayload(data).Bytes(),
 		issuerPublicKey: peer.Identity.PublicKey().String(),
 	}
 	return id, sent