diff --git a/docs/instance.rst b/docs/instance.rst
index 29273f1428c6e3f77d3a7e6c1c0a981c93738d1f..784cd5a01312a2985c3e190317186c9a39e00503 100644
--- a/docs/instance.rst
+++ b/docs/instance.rst
@@ -50,9 +50,17 @@ __ http://www.sphinx-doc.org/en/stable/ext/doctest.html
    ...   ri = json.load(infile)
    >>> inst = dm.from_raw(ri)
 
-.. class:: InstanceNode(value: Value, parinst: Optional[InstanceNode], \
+.. class:: InstanceNode(key: InstKey, value: Value, \
+	   parinst: Optional[InstanceNode], \
 	   schema_node: DataNode, timestamp: datetime.datetime)
 
+   The *key* argument is the key of the instance in the parent
+   structure, i.e. either :term:`instance name` for an
+   :class:`ObjectMember` or integer index for an
+   :class:`ArrayEntry`. The key becomes the last component of the
+   :attr:`path` attribute. Other constructor arguments contain values
+   for instance attributes of the same name.
+
    This class and its subclasses implement the *zipper* interface for
    instance data along the lines of GĂ©rard Huet's original
    paper [Hue97]_, only adapted for the specifics of JSON-like
@@ -80,6 +88,11 @@ __ http://www.sphinx-doc.org/en/stable/ext/doctest.html
 
    .. rubric:: Instance Attributes
 
+   .. attribute:: path
+
+      Path of the instance in the data tree: a tuple containing keys
+      of the ancestor nodes and the instance itself.
+
    .. attribute:: parinst
 
       Parent instance node, or ``None`` for the root node.
@@ -90,7 +103,7 @@ __ http://www.sphinx-doc.org/en/stable/ext/doctest.html
 
    .. attribute:: timestamp
 
-      The time when the instance node was last modified.
+      The date and time when the instance node was last modified.
 
    .. attribute:: value
 
@@ -103,13 +116,19 @@ __ http://www.sphinx-doc.org/en/stable/ext/doctest.html
 
    .. attribute:: namespace
 
-      The :term:`namespace identifier` of the instance node. For the root
-      node it is ``None``.
+      The :term:`namespace identifier` of the instance node.
+
+   .. attribute:: name
+
+      The :term:`instance name` of the receiver. For an
+      :class:`ArrayEntry` instance it is by definition the same as the
+      qualified name of the parent :class:`ObjectMember`.
 
    .. attribute:: qual_name
 
-      The :term:`qualified name` of the receiver. For the root node it
-      is ``None``.
+      The :term:`qualified name` of the receiver. For an
+      :class:`ArrayEntry` instance it is by definition the same as the
+      qualified name of the parent :class:`ObjectMember`.
 
    An :class:`InstanceNode` structure can be created from scratch, or
    read from JSON text using :meth:`.DataModel.from_raw` (see the
@@ -178,43 +197,60 @@ __ http://www.sphinx-doc.org/en/stable/ext/doctest.html
       the result is the value returned by Python standard function
       :class:`str`.
 
-   .. method:: is_internal() -> bool
-
-      Return ``True`` if the receiver is an instance of an internal
-      schema node, i.e. its :attr:`schema_node` is an
-      :class:`~.schema.InternalNode`. Otherwise return ``False``.
-
-      .. doctest::
+   .. automethod:: json_pointer
 
-	 >>> inst.is_internal()
-	 True
+   .. method:: __getitem__(key: InstKey) -> InstanceNode
 
-   .. automethod:: json_pointer
+      This method allows for selecting receiver's member or entry
+      using square brackets as it is usual for other Python sequence
+      types. The argument *key* is
 
-   .. method:: member(name: InstanceName) -> ObjectMember
+      * an integer index, if the receiver's value is an array
+	(negative indices are also supported), or
 
-      Return an instance node corresponding to the receiver's
-      member *name*.
+      * an :term:`instance name`, if the receiver's value is an object.
 
-      This method may raise the following exceptions:
+      The value returned by this method is either an
+      :class:`ObjectMember` or :class:`ArrayEntry`.
 
-      * :exc:`InstanceValueError` – if receiver's value is not an
-	object.
-      * :exc:`NonexistentSchemaNode` – if the schema doesn't permit
-	member *name*,
-      * :exc:`NonexistentInstance` – if member *name* isn't present in
-	the actual receiver's value,
+      This method raises :exc:`InstanceValueError` if receiver's value
+      is not structured, and :exc:`NonexistentInstance` if the member
+      or entry identified by *key* doesn't exist in the actual
+      receiver's value.
 
       .. doctest::
 
 	 >>> bag = inst['example-2:bag']
 	 >>> foo = bag['foo']
+	 >>> foo.path
+	 ('example-2:bag', 'foo')
 	 >>> foo.json_pointer()
 	 '/example-2:bag/foo'
 	 >>> bag['baz']
 	 Traceback (most recent call last):
 	 ...
 	 yangson.instance.NonexistentInstance: [/example-2:bag] member baz
+	 >>> foo6 = foo[0]
+	 >>> foo6.value['number']
+	 6
+	 >>> foo3 = foo[-1]
+	 >>> foo3.value['in-words']
+	 'three'
+	 >>> foo[2]
+	 Traceback (most recent call last):
+	 ...
+	 yangson.instance.NonexistentInstance: [/example-2:bag/foo] entry 2
+
+   .. method:: is_internal() -> bool
+
+      Return ``True`` if the receiver is an instance of an internal
+      schema node, i.e. its :attr:`schema_node` is an
+      :class:`~.schema.InternalNode`. Otherwise return ``False``.
+
+      .. doctest::
+
+	 >>> inst.is_internal()
+	 True
 
    .. method:: put_member(name: InstanceName, value: Union[RawValue, \
 	       Value], raw: bool = False) -> InstanceNode
@@ -235,7 +271,7 @@ __ http://www.sphinx-doc.org/en/stable/ext/doctest.html
 	 >>> nbar = bag.put_member('bar', False)
 	 >>> nbar.value
 	 False
-	 >>> bag.value['bar']                       # bag is unchanged
+	 >>> bag.value['bar']  # bag is unchanged
 	 True
 	 >>> e2bag = bag.put_member('baz', 3.1415926).up()  # baz is created
 	 >>> sorted(e2bag.value.keys())
@@ -279,34 +315,6 @@ __ http://www.sphinx-doc.org/en/stable/ext/doctest.html
 	 >>> foo3.json_pointer()
 	 '/example-2:bag/foo/1'
 
-   .. method:: entry(index: int) -> ArrayEntry
-
-      Return an instance node corresponding to the receiver's entry
-      whose index is specified by the *index* argument.
-
-      This method raises :exc:`InstanceValueError` if the receiver's
-      value is not an array, and :exc:`NonexistentInstance` if entry
-      *index* is not present in the receiver's value.
-
-      .. doctest::
-
-	 >>> foo6 = foo[0]
-	 >>> foo6.value['number']
-	 6
-
-   .. method:: last_entry() -> ArrayEntry
-
-      Return an instance node corresponding to the receiver's last entry.
-
-      :exc:`InstanceValueError` is raised if the receiver's value is
-      not an array, and :exc:`NonexistentInstance` is raised if the
-      receiver is an empty array.
-
-      .. doctest::
-
-	 >>> foo.last_entry().json_pointer()
-	 '/example-2:bag/foo/1'
-
    .. method:: delete_entry(index: int) -> InstanceNode
 
       Return a new instance node that is an exact copy of the
@@ -496,13 +504,7 @@ __ http://www.sphinx-doc.org/en/stable/ext/doctest.html
 .. autoclass:: RootNode(value: Value, schema_node: SchemaNode, timestamp: datetime.datetime)
    :show-inheritance:
 
-   .. rubric:: Instance Attributes
-
-   .. attribute:: name
-
-      The :term:`instance name` of the root node is always ``None``.
-
-.. class:: ObjectMember(name: InstanceName, siblings: \
+.. class:: ObjectMember(key: InstanceName, siblings: \
 	   Dict[InstanceName, Value], value: Value, parinst: \
 	   InstanceNode, schema_node: DataNode, timestamp: \
 	   datetime.datetime)
@@ -515,10 +517,6 @@ __ http://www.sphinx-doc.org/en/stable/ext/doctest.html
 
    .. rubric:: Instance Attributes
 
-   .. attribute:: name
-
-      Instance name of the receiver as a member of the parent object.
-
    .. attribute:: siblings
 
       Dictionary of the receiver's siblings (other members of the
@@ -540,7 +538,7 @@ __ http://www.sphinx-doc.org/en/stable/ext/doctest.html
 	 >>> foo.sibling('bar').json_pointer()
 	 '/example-2:bag/bar'
 
-.. class:: ArrayEntry(before: List[Value], after: List[Value], value: \
+.. class:: ArrayEntry(key: int, before: List[Value], after: List[Value], value: \
 	   Value, parinst: InstanceNode, schema_node: \
 	   DataNode, timestamp: datetime.datetime)
 
@@ -571,15 +569,7 @@ __ http://www.sphinx-doc.org/en/stable/ext/doctest.html
 
 	 >>> foo6.index
 	 0
-
-   .. attribute:: name
-
-      The :term:`instance name` of an array entry is by definition the
-      same as the instance name of the parent array.
-
-      .. doctest::
-
-	 >>> foo6.name
+	 >>> foo6.name  # inherited from parent
 	 'foo'
 
    .. rubric:: Public Methods
diff --git a/tests/test_model.py b/tests/test_model.py
index 3fac2b0428af06cf6672dad1133a078180e0127a..83e0df9f2bebc44bc5a7c14d6dd62a037c60b7d1 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -281,7 +281,7 @@ def test_instance(instance):
     assert hi == hix
     assert hi != hid
     conta = instance["test:contA"]
-    la1 = conta["listA"].last_entry()
+    la1 = conta["listA"][-1]
     lt = conta["testb:leafT"]
     assert la1.index == 1
     tbln = conta["testb:leafN"]
diff --git a/yangson/instance.py b/yangson/instance.py
index 0c21c494a04c7aa7ad325b8fc6d715f5db31d610..2a32edc574431b9e709dee318863e3917ead5680 100644
--- a/yangson/instance.py
+++ b/yangson/instance.py
@@ -48,6 +48,10 @@ from .parser import EndOfInput, Parser, UnexpectedInput
 from .typealiases import *
 from .typealiases import _Singleton
 
+__all__ = ["InstanceNode", "RootNode", "ObjectMember", "ArrayEntry",
+               "InstanceIdParser", "ResourceIdParser", "InstanceRoute",
+               "InstanceException", "InstanceValueError", "NonexistentInstance"]
+
 class LinkedList:
     """Persistent linked list of instance values."""
 
@@ -58,7 +62,7 @@ class LinkedList:
         Args:
             vals: Python list of instance values.
         """
-        res = _EmptyList()
+        res = EmptyList()
         for v in vals[::-1]:
             res = res.cons(v)
         return res
@@ -101,7 +105,7 @@ class LinkedList:
         """
         return (self.head, self.tail)
 
-class _EmptyList(LinkedList, metaclass=_Singleton):
+class EmptyList(LinkedList, metaclass=_Singleton):
     """Singleton class representing the empty linked list."""
 
     def __init__(self):
@@ -144,6 +148,10 @@ class InstanceNode:
         return (str(self.value) if isinstance(self.value, StructuredValue) else
                 sn.type.canonical_string(self.value))
 
+    def json_pointer(self) -> str:
+        """Return JSON Pointer [RFC6901]_ of the receiver."""
+        return "/" + "/".join([str(c) for c in self.path])
+
     def __getitem__(self, key: InstKey) -> "InstanceNode":
         """Return member or entry with the given key.
 
@@ -166,19 +174,6 @@ class InstanceNode:
         """
         return isinstance(self.schema_node, InternalNode)
 
-    def json_pointer(self) -> str:
-        """Return JSON Pointer [RFC6901]_ of the receiver."""
-        return "/" + "/".join([str(c) for c in self.path])
-
-    def _member(self, name: InstanceName) -> "ObjectMember":
-        sibs = self.value.copy()
-        try:
-            return ObjectMember(
-                name, sibs, sibs.pop(name), self,
-                self._member_schema_node(name), self.value.timestamp)
-        except KeyError:
-            raise NonexistentInstance(self, "member " + name) from None
-
     def put_member(self, name: InstanceName, value: Value,
                    raw: bool = False) -> "InstanceNode":
         """Return receiver's member with a new value.
@@ -250,33 +245,6 @@ class InstanceNode:
         except TypeError:
             raise InstanceValueError(self, "lookup on non-list") from None
 
-    def _entry(self, index: int) -> "ArrayEntry":
-        val = self.value
-        try:
-            return ArrayEntry(index, LinkedList.from_list(val[:index]),
-                                  LinkedList.from_list(val[index+1:]),
-                                  val[index], self, self.schema_node,
-                                  val.timestamp)
-        except (IndexError, TypeError):
-            raise NonexistentInstance(self, "entry " + str(index)) from None
-
-    def last_entry(self) -> "ArrayEntry":
-        """Return an instance node corresponding to the receiver's last entry.
-
-        Raises:
-            InstanceValueError: If the receiver's value is not an array.
-            NonexistentInstance: If the receiver's value is an empty array.
-        """
-        val = self.value
-        if not isinstance(val, ArrayValue):
-            raise InstanceValueError(self, "last entry of non-array")
-        try:
-            return ArrayEntry(
-                len(val) - 1, LinkedList.from_list(val[:-1]),
-                _EmptyList(), val[-1], self,self.schema_node, val.timestamp)
-        except IndexError:
-            raise NonexistentInstance(self, "last of empty") from None
-
     def delete_entry(self, index: int) -> "InstanceNode":
         """Return a copy of the receiver with an entry deleted from its value.
 
@@ -367,6 +335,25 @@ class InstanceNode:
         """
         self.schema_node.validate(self, ctype)
 
+    def add_defaults(self, ctype: ContentType = None) -> "InstanceNode":
+        """Return the receiver with defaults added recursively to its value.
+
+        Args:
+            ctype: Content type of the defaults to be added. If it is
+                ``None``, the content type will be the same as receiver's.
+        """
+        sn = self.schema_node
+        val = self.value
+        if not (isinstance(val, ObjectValue) and isinstance(sn, InternalNode)):
+            return self
+        res = self
+        if val:
+            for mn in val:
+                m = res._member(mn) if res is self else res.sibling(mn)
+                res = m.add_defaults(ctype)
+            res = res.up()
+        return sn._add_defaults(res, ctype)
+
     def raw_value(self) -> RawValue:
         """Return receiver's value in a raw form (ready for JSON encoding)."""
         if isinstance(self.value, ObjectValue):
@@ -386,24 +373,25 @@ class InstanceNode:
             res = self.schema_node.type.to_raw(self.value)
         return res
 
-    def add_defaults(self, ctype: ContentType = None) -> "InstanceNode":
-        """Return the receiver with defaults added recursively to its value.
+    def _member(self, name: InstanceName) -> "ObjectMember":
+        sibs = self.value.copy()
+        try:
+            return ObjectMember(
+                name, sibs, sibs.pop(name), self,
+                self._member_schema_node(name), self.value.timestamp)
+        except KeyError:
+            raise NonexistentInstance(self, "member " + name) from None
 
-        Args:
-            ctype: Content type of the defaults to be added. If it is
-                ``None``, the content type will be the same as receiver's.
-        """
-        sn = self.schema_node
+    def _entry(self, index: int) -> "ArrayEntry":
         val = self.value
-        if not (isinstance(val, ObjectValue) and isinstance(sn, InternalNode)):
-            return self
-        res = self
-        if val:
-            for mn in val:
-                m = res._member(mn) if res is self else res.sibling(mn)
-                res = m.add_defaults(ctype)
-            res = res.up()
-        return sn._add_defaults(res, ctype)
+        i = len(val) + index if index < 0 else index
+        try:
+            return ArrayEntry(i, LinkedList.from_list(val[:i]),
+                                  LinkedList.from_list(val[i+1:]),
+                                  val[index], self, self.schema_node,
+                                  val.timestamp)
+        except (IndexError, TypeError):
+            raise NonexistentInstance(self, "entry " + str(index)) from None
 
     def _peek_schema_route(self, sroute: SchemaRoute) -> Value:
         irt = InstanceRoute()
@@ -523,10 +511,10 @@ class RootNode(InstanceNode):
 class ObjectMember(InstanceNode):
     """This class represents an object member."""
 
-    def __init__(self, name: InstanceName, siblings: Dict[InstanceName, Value],
+    def __init__(self, key: InstanceName, siblings: Dict[InstanceName, Value],
                  value: Value, parinst: InstanceNode,
                  schema_node: "DataNode", timestamp: datetime ):
-        super().__init__(name, value, parinst, schema_node, timestamp)
+        super().__init__(key, value, parinst, schema_node, timestamp)
         self.siblings = siblings # type: Dict[InstanceName, Value]
         """Sibling members within the parent object."""
 
@@ -591,10 +579,10 @@ class ObjectMember(InstanceNode):
 class ArrayEntry(InstanceNode):
     """This class represents an array entry."""
 
-    def __init__(self, index: int, before: LinkedList, after: LinkedList,
+    def __init__(self, key: int, before: LinkedList, after: LinkedList,
                      value: Value, parinst: InstanceNode,
                      schema_node: "DataNode", timestamp: datetime = None):
-        super().__init__(index, value, parinst, schema_node, timestamp)
+        super().__init__(key, value, parinst, schema_node, timestamp)
         self.before = before # type: LinkedList
         """Preceding entries of the parent array."""
         self.after = after # type: LinkedList
@@ -756,33 +744,28 @@ class InstanceRoute(list):
 
 class InstanceSelector:
     """Components of instance identifers."""
-    pass
 
-class MemberName(InstanceSelector):
-    """Selectors of object members."""
-
-    def __init__(self, name: InstanceName):
+    def __init__(self, key: InstKey):
         """Initialize the class instance.
 
         Args:
-            name: Member name.
+            key: Member name or entry index.
         """
-        self.name = name
+        self.key = key
 
-    def __str__(self) -> str:
-        """Return a string representation of the receiver."""
-        return "/" + self.name
+    def __eq__(self, other: "InstanceSelector") -> bool:
+        return self.key == other.key
 
-    def __eq__(self, other: "MemberName") -> bool:
-        return self.name == other.name
-
-    def peek_step(self, obj: ObjectValue) -> Value:
-        """Return the member of `obj` addressed by the receiver.
+    def peek_step(self, val: StructuredValue) -> Value:
+        """Return the entry of `arr` addressed by the receiver.
 
         Args:
-            obj: Current object.
+            val: Current value (object or array).
         """
-        return obj.get(self.name)
+        try:
+            return val[self.key]
+        except (IndexError, KeyError, TypeError):
+            return None
 
     def goto_step(self, inst: InstanceNode) -> InstanceNode:
         """Return member instance of `inst` addressed by the receiver.
@@ -790,44 +773,21 @@ class MemberName(InstanceSelector):
         Args:
             inst: Current instance.
         """
-        return inst._member(self.name)
-
-class EntryIndex(InstanceSelector):
-    """Numeric selectors for a list or leaf-list entry."""
+        return inst[self.key]
 
-    def __init__(self, index: int):
-        """Initialize the class instance.
-
-        Args:
-            index: Index of an entry.
-        """
-        self.index = index
+class MemberName(InstanceSelector):
+    """Selectors of object members."""
 
     def __str__(self) -> str:
         """Return a string representation of the receiver."""
-        return "[{0:d}]".format(self.index)
-
-    def __eq__(self, other: "EntryIndex") -> bool:
-        return self.index == other.index
-
-    def peek_step(self, arr: ArrayValue) -> Value:
-        """Return the entry of `arr` addressed by the receiver.
-
-        Args:
-            arr: Current array.
-        """
-        try:
-            return arr[self.index]
-        except IndexError:
-            return None
+        return "/" + self.key
 
-    def goto_step(self, inst: InstanceNode) -> InstanceNode:
-        """Return member instance of `inst` addressed by the receiver.
+class EntryIndex(InstanceSelector):
+    """Numeric selectors for a list or leaf-list entry."""
 
-        Args:
-            inst: Current instance.
-        """
-        return inst._entry(self.index)
+    def __str__(self) -> str:
+        """Return a string representation of the receiver."""
+        return "[{0:d}]".format(self.key)
 
 class EntryValue(InstanceSelector):
     """Value-based selectors of an array entry."""