diff --git a/docs/source/backend/ast.rst b/docs/source/backend/ast.rst
index 41f23016664002fd100544d72c509f9f73d72bdd..44f8f25409ad08cff1d550dddcd9099bbbc798df 100644
--- a/docs/source/backend/ast.rst
+++ b/docs/source/backend/ast.rst
@@ -2,29 +2,30 @@
 Abstract Syntax Tree
 ********************
 
-Inheritance Diagramm
-====================
+API Documentation
+=================
+
+Inheritance Diagram
+-------------------
 
 .. inheritance-diagram:: pystencils.backend.ast.astnode.PsAstNode pystencils.backend.ast.structural pystencils.backend.ast.expressions pystencils.backend.extensions.foreign_ast
     :top-classes: pystencils.types.PsAstNode
     :parts: 1
 
-
 Base Classes
-============
+------------
 
 .. automodule:: pystencils.backend.ast.astnode
     :members:
 
 Structural Nodes
-================
+----------------
 
 .. automodule:: pystencils.backend.ast.structural
     :members:
 
-
 Expressions
-===========
+-----------
 
 .. automodule:: pystencils.backend.ast.expressions
     :members:
diff --git a/docs/source/backend/index.rst b/docs/source/backend/index.rst
index b3de9dbf65ce351b82e54d5927ab703088092da3..70ed684c69e494a2c9d72f91fdcc62641f4acd69 100644
--- a/docs/source/backend/index.rst
+++ b/docs/source/backend/index.rst
@@ -15,6 +15,7 @@ who wish to customize or extend the behaviour of the code generator in their app
     translation
     platforms
     transformations
+    output
     jit
     extensions
 
diff --git a/docs/source/backend/objects.rst b/docs/source/backend/objects.rst
index a39f4c24b1e7b0ceae4f24bdc5b8869b69c080ac..11cf8ea5e53446a0db9dfac18c983e46eaf3bf36 100644
--- a/docs/source/backend/objects.rst
+++ b/docs/source/backend/objects.rst
@@ -40,18 +40,18 @@ two `PsSymbol` instances with the same name and data type will in general *not*
 In fact, most of the time, it is an error to have two identical symbol instances active.
 
 Creating Symbols
-----------------
+^^^^^^^^^^^^^^^^
 
 During kernel translation, symbols never exist in isolation, but should always be managed by a `KernelCreationContext`.
-Symbols can be created and retrieved using `KernelCreationContext.add_symbol` and `KernelCreationContext.find_symbol`.
-A symbol can also be duplicated using `KernelCreationContext.duplicate_symbol`, which assigns a new name to the symbol's copy.
+Symbols can be created and retrieved using `add_symbol <KernelCreationContext.add_symbol>` and `find_symbol <KernelCreationContext.find_symbol>`.
+A symbol can also be duplicated using `duplicate_symbol <KernelCreationContext.duplicate_symbol>`, which assigns a new name to the symbol's copy.
 The `KernelCreationContext` keeps track of all existing symbols during a kernel translation run
 and makes sure that no name and data type conflicts may arise.
 
 Never call the constructor of `PsSymbol` directly unless you really know what you are doing.
 
 Symbol Properties
------------------
+^^^^^^^^^^^^^^^^^
 
 Symbols can be annotated with arbitrary information using *symbol properties*.
 Each symbol property type must be a subclass of `PsSymbolProperty`.
@@ -64,6 +64,7 @@ For example, this snippet defines a property type that models pointer alignment
     @dataclass(frozen=True)
     class AlignmentProperty(UniqueSymbolProperty)
         """Require this pointer symbol to be aligned at a particular byte boundary."""
+        
         byte_boundary: int
 
 Inheriting from `UniqueSymbolProperty` ensures that at most one property of this type can be attached to
@@ -77,10 +78,34 @@ It then becomes the responsibility of the runtime system embedding the kernel to
 To make sure this information becomes visible, any properties attached to symbols exposed as kernel parameters will also
 be added to their respective `KernelParameter` instance.
 
-Constants and Literals
-======================
-
+Buffers
+-------
 
+Buffers, as represented by the `PsBuffer` class, represent contiguous, n-dimensional, linearized cuboid blocks of memory.
+Each buffer has a fixed name and element data type,
+and will be represented in the IR via three sets of symbols:
+
+- The *base pointer* is a symbol of pointer type which points into the buffer's underlying memory area.
+  Each buffer has at least one, its primary base pointer, whose pointed-to type must be the same as the
+  buffer's element type. There may be additional base pointers pointing into subsections of that memory.
+  These additional base pointers may also have deviating data types, as is for instance required for
+  type erasure in certain cases.
+  To communicate its role to the code generation system,
+  each base pointer needs to be marked as such using the `BufferBasePtr` property,
+  .
+- The buffer *shape* defines the size of the buffer in each dimension. Each shape entry is either a `symbol <PsSymbol>`
+  or a `constant <PsConstant>`.
+- The buffer *strides* define the step size to go from one entry to the next in each dimension.
+  Like the shape, each stride entry is also either a symbol or a constant.
+
+The shape and stride symbols must all have the same data type, which will be stored as the buffer's index data type.
+
+Creating and Managing Buffers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Similarily to symbols, buffers are typically managed by the `KernelCreationContext`, which associates each buffer
+to a front-end `Field`. Buffers for fields can be obtained using `get_buffer <KernelCreationContext.get_buffer>`.
+The context makes sure to avoid name conflicts between buffers.
 
 API Documentation
 =================
diff --git a/docs/source/backend/output.rst b/docs/source/backend/output.rst
new file mode 100644
index 0000000000000000000000000000000000000000..9875e257b0ff76de29370dd40a0ab0772ad1fec1
--- /dev/null
+++ b/docs/source/backend/output.rst
@@ -0,0 +1,6 @@
+*********************
+Code Generator Output
+*********************
+
+.. automodule:: pystencils.backend.kernelfunction
+    :members:
diff --git a/src/pystencils/backend/memory.py b/src/pystencils/backend/memory.py
index ad28cd3c73f2c9f8f7f18865d20ee1bff5222999..9b72a4e4337f1de152291b3287cffb612999a786 100644
--- a/src/pystencils/backend/memory.py
+++ b/src/pystencils/backend/memory.py
@@ -3,7 +3,7 @@ from typing import Sequence
 from itertools import chain
 from dataclasses import dataclass
 
-from ..types import PsType, PsTypeError, deconstify, PsIntegerType
+from ..types import PsType, PsTypeError, deconstify, PsIntegerType, PsPointerType
 from .exceptions import PsInternalCompilerError
 from .constants import PsConstant
 from .properties import PsSymbolProperty, UniqueSymbolProperty
@@ -119,6 +119,19 @@ class PsBuffer:
         shape: Sequence[PsSymbol | PsConstant],
         strides: Sequence[PsSymbol | PsConstant],
     ):
+        bptr_type = base_ptr.get_dtype()
+        
+        if not isinstance(bptr_type, PsPointerType):
+            raise ValueError(
+                f"Type of buffer base pointer {base_ptr} was not a pointer type: {bptr_type}"
+            )
+        
+        if bptr_type.base_type != element_type:
+            raise ValueError(
+                f"Base type of primary buffer base pointer {base_ptr} "
+                f"did not equal buffer element type {element_type}."
+            )
+
         if len(shape) != len(strides):
             raise ValueError("Buffer shape and stride tuples must have the same length")
 
@@ -148,30 +161,37 @@ class PsBuffer:
 
     @property
     def name(self):
+        """The buffer's name"""
         return self._name
 
     @property
     def base_pointer(self) -> PsSymbol:
+        """Primary base pointer"""
         return self._base_ptr
 
     @property
     def shape(self) -> tuple[PsSymbol | PsConstant, ...]:
+        """Buffer shape symbols and/or constants"""
         return self._shape
 
     @property
     def strides(self) -> tuple[PsSymbol | PsConstant, ...]:
+        """Buffer stride symbols and/or constants"""
         return self._strides
 
     @property
     def dim(self) -> int:
+        """Dimensionality of this buffer"""
         return len(self._shape)
 
     @property
     def index_type(self) -> PsIntegerType:
+        """Index data type of this buffer; i.e. data type of its shape and stride symbols"""
         return self._index_dtype
 
     @property
     def element_type(self) -> PsType:
+        """Element type of this buffer"""
         return self._element_type
 
     def __repr__(self) -> str: