diff --git a/pygit2/decl/submodule.h b/pygit2/decl/submodule.h
index 4641dfb10..450ad526b 100644
--- a/pygit2/decl/submodule.h
+++ b/pygit2/decl/submodule.h
@@ -1,5 +1,22 @@
 #define GIT_SUBMODULE_UPDATE_OPTIONS_VERSION ...
 
+typedef enum {
+	GIT_SUBMODULE_STATUS_IN_HEAD           = (1u << 0),
+	GIT_SUBMODULE_STATUS_IN_INDEX          = (1u << 1),
+	GIT_SUBMODULE_STATUS_IN_CONFIG         = (1u << 2),
+	GIT_SUBMODULE_STATUS_IN_WD             = (1u << 3),
+	GIT_SUBMODULE_STATUS_INDEX_ADDED       = (1u << 4),
+	GIT_SUBMODULE_STATUS_INDEX_DELETED     = (1u << 5),
+	GIT_SUBMODULE_STATUS_INDEX_MODIFIED    = (1u << 6),
+	GIT_SUBMODULE_STATUS_WD_UNINITIALIZED  = (1u << 7),
+	GIT_SUBMODULE_STATUS_WD_ADDED          = (1u << 8),
+	GIT_SUBMODULE_STATUS_WD_DELETED        = (1u << 9),
+	GIT_SUBMODULE_STATUS_WD_MODIFIED       = (1u << 10),
+	GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED = (1u << 11),
+	GIT_SUBMODULE_STATUS_WD_WD_MODIFIED    = (1u << 12),
+	GIT_SUBMODULE_STATUS_WD_UNTRACKED      = (1u << 13),
+} git_submodule_status_t;
+
 typedef struct git_submodule_update_options {
 	unsigned int version;
 	git_checkout_options checkout_opts;
@@ -34,8 +51,24 @@ int git_submodule_open(
 	git_repository **repo,
 	git_submodule *submodule);
 
+int git_submodule_init(git_submodule *submodule, int overwrite);
+int git_submodule_sync(git_submodule *submodule);
+int git_submodule_reload(git_submodule *submodule, int force);
+int git_submodule_status(unsigned int *status, git_repository *repo, const char *name, git_submodule_ignore_t ignore);
+
+int git_submodule_add_to_index(git_submodule *submodule, int write_index);
+
 const char * git_submodule_name(git_submodule *submodule);
 const char * git_submodule_path(git_submodule *submodule);
 const char * git_submodule_url(git_submodule *submodule);
 const char * git_submodule_branch(git_submodule *submodule);
+git_submodule_ignore_t git_submodule_ignore(git_submodule *submodule);
+git_submodule_recurse_t git_submodule_fetch_recurse_submodules(git_submodule *submodule);
 const git_oid * git_submodule_head_id(git_submodule *submodule);
+const git_oid * git_submodule_index_id(git_submodule *submodule);
+const git_oid * git_submodule_wd_id(git_submodule *submodule);
+
+int git_submodule_set_url(git_repository *repo, const char *name, const char *url);
+int git_submodule_set_branch(git_repository *repo, const char *name, const char *branch);
+int git_submodule_set_ignore(git_repository *repo, const char *name, git_submodule_ignore_t ignore);
+int git_submodule_set_fetch_recurse_submodules(git_repository *repo, const char *name, git_submodule_recurse_t fetch_recurse_submodules);
diff --git a/pygit2/decl/types.h b/pygit2/decl/types.h
index 8770da7a5..5be5ceacc 100644
--- a/pygit2/decl/types.h
+++ b/pygit2/decl/types.h
@@ -48,6 +48,15 @@ typedef struct {
 typedef int (*git_transport_message_cb)(const char *str, int len, void *payload);
 typedef int (*git_transport_certificate_check_cb)(git_cert *cert, int valid, const char *host, void *payload);
 
+typedef enum {
+	GIT_SUBMODULE_UPDATE_CHECKOUT = 1,
+	GIT_SUBMODULE_UPDATE_REBASE   = 2,
+	GIT_SUBMODULE_UPDATE_MERGE    = 3,
+	GIT_SUBMODULE_UPDATE_NONE     = 4,
+
+	GIT_SUBMODULE_UPDATE_DEFAULT  = 0
+} git_submodule_update_t;
+
 typedef enum {
 	GIT_SUBMODULE_IGNORE_UNSPECIFIED  = -1,
 
@@ -56,3 +65,9 @@ typedef enum {
 	GIT_SUBMODULE_IGNORE_DIRTY     = 3,
 	GIT_SUBMODULE_IGNORE_ALL       = 4,
 } git_submodule_ignore_t;
+
+typedef enum {
+	GIT_SUBMODULE_RECURSE_NO = 0,
+	GIT_SUBMODULE_RECURSE_YES = 1,
+	GIT_SUBMODULE_RECURSE_ONDEMAND = 2,
+} git_submodule_recurse_t;
diff --git a/pygit2/repository.py b/pygit2/repository.py
index 4af400991..6389e5af0 100644
--- a/pygit2/repository.py
+++ b/pygit2/repository.py
@@ -128,7 +128,7 @@ def add_submodule(self, url, path, link=True, callbacks=None):
         Parameters:
 
         url
-            The URL of the submdoule.
+            The URL of the submodule.
 
         path
             The path within the parent repository to add the submodule
@@ -184,16 +184,9 @@ def update_submodules(self, submodules=None, init=False, callbacks=None):
         if submodules is None:
             submodules = self.listall_submodules()
 
-        # prepare options
-        opts = ffi.new('git_submodule_update_options *')
-        C.git_submodule_update_init_options(opts, C.GIT_SUBMODULE_UPDATE_OPTIONS_VERSION)
-
-        with git_fetch_options(callbacks, opts=opts.fetch_opts) as payload:
-            i = 1 if init else 0
-            for submodule in submodules:
-                submodule_instance = self.lookup_submodule(submodule)
-                err = C.git_submodule_update(submodule_instance._subm, i, opts)
-                payload.check_error(err)
+        for submodule in submodules:
+            submodule_instance = self.lookup_submodule(submodule)
+            submodule_instance.update(init, callbacks)
 
         return None
 
diff --git a/pygit2/submodule.py b/pygit2/submodule.py
index 0d0e735e5..1759f6dfe 100644
--- a/pygit2/submodule.py
+++ b/pygit2/submodule.py
@@ -24,8 +24,46 @@
 # Boston, MA 02110-1301, USA.
 
 from ._pygit2 import Oid
+from .callbacks import git_fetch_options
 from .errors import check_error
 from .ffi import ffi, C
+from .utils import to_bytes
+
+
+# GIT_SUBMODULE_UPDATE_*
+GIT_SUBMODULE_UPDATE_CHECKOUT = C.GIT_SUBMODULE_UPDATE_CHECKOUT
+GIT_SUBMODULE_UPDATE_REBASE   = C.GIT_SUBMODULE_UPDATE_REBASE
+GIT_SUBMODULE_UPDATE_MERGE    = C.GIT_SUBMODULE_UPDATE_MERGE
+GIT_SUBMODULE_UPDATE_NONE     = C.GIT_SUBMODULE_UPDATE_NONE
+GIT_SUBMODULE_UPDATE_DEFAULT  = C.GIT_SUBMODULE_UPDATE_DEFAULT
+
+# GIT_SUBMODULE_RECURSE_*
+GIT_SUBMODULE_RECURSE_NO       = C.GIT_SUBMODULE_RECURSE_NO
+GIT_SUBMODULE_RECURSE_YES      = C.GIT_SUBMODULE_RECURSE_YES
+GIT_SUBMODULE_RECURSE_ONDEMAND = C.GIT_SUBMODULE_RECURSE_ONDEMAND
+
+# GIT_SUBMODULE_IGNORE_*
+GIT_SUBMODULE_IGNORE_UNSPECIFIED = C.GIT_SUBMODULE_IGNORE_UNSPECIFIED
+GIT_SUBMODULE_IGNORE_NONE        = C.GIT_SUBMODULE_IGNORE_NONE
+GIT_SUBMODULE_IGNORE_UNTRACKED   = C.GIT_SUBMODULE_IGNORE_UNTRACKED
+GIT_SUBMODULE_IGNORE_DIRTY       = C.GIT_SUBMODULE_IGNORE_DIRTY
+GIT_SUBMODULE_IGNORE_ALL         = C.GIT_SUBMODULE_IGNORE_ALL
+
+# GIT_SUBMODULE_STATUS_*
+GIT_SUBMODULE_STATUS_IN_HEAD           = C.GIT_SUBMODULE_STATUS_IN_HEAD
+GIT_SUBMODULE_STATUS_IN_INDEX          = C.GIT_SUBMODULE_STATUS_IN_INDEX
+GIT_SUBMODULE_STATUS_IN_CONFIG         = C.GIT_SUBMODULE_STATUS_IN_CONFIG
+GIT_SUBMODULE_STATUS_IN_WD             = C.GIT_SUBMODULE_STATUS_IN_WD
+GIT_SUBMODULE_STATUS_INDEX_ADDED       = C.GIT_SUBMODULE_STATUS_INDEX_ADDED
+GIT_SUBMODULE_STATUS_INDEX_DELETED     = C.GIT_SUBMODULE_STATUS_INDEX_DELETED
+GIT_SUBMODULE_STATUS_INDEX_MODIFIED    = C.GIT_SUBMODULE_STATUS_INDEX_MODIFIED
+GIT_SUBMODULE_STATUS_WD_UNINITIALIZED  = C.GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
+GIT_SUBMODULE_STATUS_WD_ADDED          = C.GIT_SUBMODULE_STATUS_WD_ADDED
+GIT_SUBMODULE_STATUS_WD_DELETED        = C.GIT_SUBMODULE_STATUS_WD_DELETED
+GIT_SUBMODULE_STATUS_WD_MODIFIED       = C.GIT_SUBMODULE_STATUS_WD_MODIFIED
+GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED = C.GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED
+GIT_SUBMODULE_STATUS_WD_WD_MODIFIED    = C.GIT_SUBMODULE_STATUS_WD_WD_MODIFIED
+GIT_SUBMODULE_STATUS_WD_UNTRACKED      = C.GIT_SUBMODULE_STATUS_WD_UNTRACKED
 
 
 class Submodule:
@@ -50,12 +88,95 @@ def open(self):
 
         return self._repo._from_c(crepo[0], True)
 
+    def init(self, force=False):
+        """Copy submodule info into ".git/config" file.
+
+        Parameters:
+
+        force
+            Force entry to be updated.
+        """
+        cforce = 1 if force else 0
+        err = C.git_submodule_init(self._subm, cforce)
+        check_error(err)
+
+    def update(self, init=False, callbacks=None):
+        """Update a submodule.
+
+        This will clone a missing submodule and checkout the subrepository to the commit
+        specified in the index of the containing repository. If the submodule repository
+        doesn't contain the target commit (e.g. because fetchRecurseSubmodules isn't set),
+        then the submodule is fetched using the fetch options supplied in options.
+
+        Parameters:
+
+        init
+            If the submodule is not initialized, setting this flag to true will initialize
+            the submodule before updating. Otherwise, this will return an error if attempting
+            to update an uninitialzed repository. but setting this to true forces them to be
+            updated.
+
+        callbacks
+            Configuration options for the update."""
+        opts = ffi.new('git_submodule_update_options *')
+        C.git_submodule_update_init_options(opts, C.GIT_SUBMODULE_UPDATE_OPTIONS_VERSION)
+
+        with git_fetch_options(callbacks, opts=opts.fetch_opts) as payload:
+            i = 1 if init else 0
+            err = C.git_submodule_update(self._subm, i, opts)
+            payload.check_error(err)
+
+    def sync(self):
+        """Copy submodule remote info into submodule repo."""
+        err = C.git_submodule_sync(self._subm)
+        check_error(err)
+
+    def reload(self, force=False):
+        """Reread submodule info from config, index, and HEAD.
+
+        Parameters:
+
+        force
+            Force reload even if the data doesn't seem out of date.
+        """
+        cforce = 1 if force else 0
+        err = C.git_submodule_reload(self._subm, cforce)
+        check_error(err)
+
+    def add_to_index(self, write_index=False):
+        """Add current submodule HEAD commit to index of superproject.
+
+        Parameters:
+
+        write_index
+            Immediately write the index file.
+        """
+        cwrite_index = 1 if write_index else 0
+        err = C.git_submodule_add_to_index(self._subm, cwrite_index)
+        check_error(err)
+
+    def status(self, ignore=GIT_SUBMODULE_IGNORE_UNSPECIFIED):
+        """Get the status for a submodule."""
+        crepo = self._repo._repo
+        cname = ffi.new('char[]', to_bytes(self.name))
+        cstatus = ffi.new('uint *')
+
+        err = C.git_submodule_status(cstatus, crepo, cname, ignore)
+        check_error(err)
+
+        return cstatus[0]
+
     @property
     def name(self):
         """Name of the submodule."""
         name = C.git_submodule_name(self._subm)
         return ffi.string(name).decode('utf-8')
 
+    @property
+    def owner(self):
+        """The parent repository"""
+        return self._repo
+
     @property
     def path(self):
         """Path of the submodule."""
@@ -68,14 +189,91 @@ def url(self):
         url = C.git_submodule_url(self._subm)
         return ffi.string(url).decode('utf-8')
 
+    @url.setter
+    def url(self, u):
+        """Set the URL for the submodule in the configuration."""
+        crepo = self._repo._repo
+        cname = ffi.new('char[]', to_bytes(self.name))
+        curl = ffi.new('char[]', to_bytes(u))
+
+        err = C.git_submodule_set_url(crepo, cname, curl)
+        check_error(err)
+
     @property
     def branch(self):
         """Branch that is to be tracked by the submodule."""
         branch = C.git_submodule_branch(self._subm)
         return ffi.string(branch).decode('utf-8')
 
+    @branch.setter
+    def branch(self, b):
+        """Set the branch for the submodule in the configuration."""
+        crepo = self._repo._repo
+        cname = ffi.new('char[]', to_bytes(self.name))
+        cbranch = ffi.new('char[]', to_bytes(b))
+
+        err = C.git_submodule_set_branch(crepo, cname, cbranch)
+        check_error(err)
+
     @property
     def head_id(self):
         """Head of the submodule."""
         head = C.git_submodule_head_id(self._subm)
         return Oid(raw=bytes(ffi.buffer(head)[:]))
+
+    @property
+    def index_id(self):
+        """Index OID of the submodule."""
+        oid = C.git_submodule_index_id(self._subm)
+        return Oid(raw=bytes(ffi.buffer(oid)[:]))
+
+    @property
+    def wd_id(self):
+        """Current working directory OID of the submodule."""
+        oid = C.git_submodule_wd_id(self._subm)
+        return Oid(raw=bytes(ffi.buffer(oid)[:]))
+
+    @property
+    def ignore_rule(self):
+        """Get the ignore rule that will be used for the submodule."""
+        res = C.git_submodule_ignore(self._subm)
+        return res
+
+    @ignore_rule.setter
+    def ignore_rule(self, i):
+        """Set the ignore rule for the submodule in the configuration."""
+        crepo = self._repo._repo
+        cname = ffi.new('char[]', to_bytes(self.name))
+
+        err = C.git_submodule_set_ignore(crepo, cname, i)
+        check_error(err)
+
+
+    @property
+    def fetch_recurse_rule(self):
+        """Get the fetchRecurseSubmodules rule for a submodule."""
+        res = C.git_submodule_fetch_recurse_submodules(self._subm)
+        return res
+
+    @fetch_recurse_rule.setter
+    def fetch_recurse_rule(self, f):
+        """Set the fetchRecurseSubmodules rule for a submodule in the configuration."""
+        crepo = self._repo._repo
+        cname = ffi.new('char[]', to_bytes(self.name))
+
+        C.git_submodule_set_fetch_recurse_submodules(crepo, cname, f)
+
+    @property
+    def update_rule(self):
+        """Get the update rule that will be used for the submodule."""
+        res = C.git_submodule_update_strategy(self._subm)
+        return res
+
+    @update_rule.setter
+    def update_rule(self, u):
+        """Set the ignore rule for the submodule in the configuration."""
+        crepo = self._repo._repo
+        cname = ffi.new('char[]', to_bytes(self.name))
+
+        err = C.git_submodule_set_update(crepo, cname, u)
+        check_error(err)