diff --git a/discord/ext/commands/bot.py b/discord/ext/commands/bot.py
index 733cfec26..3f5292771 100644
--- a/discord/ext/commands/bot.py
+++ b/discord/ext/commands/bot.py
@@ -93,7 +93,7 @@ def _default_help_command(ctx, *commands : str):
         if name in bot.cogs:
             command = bot.cogs[name]
         else:
-            command = bot.commands.get(name)
+            command = bot.all_commands.get(name)
             if command is None:
                 yield from destination.send(bot.command_not_found.format(name))
                 return
@@ -101,7 +101,7 @@ def _default_help_command(ctx, *commands : str):
         pages = yield from bot.formatter.format_help_for(ctx, command)
     else:
         name = _mention_pattern.sub(repl, commands[0])
-        command = bot.commands.get(name)
+        command = bot.all_commands.get(name)
         if command is None:
             yield from destination.send(bot.command_not_found.format(name))
             return
@@ -109,7 +109,7 @@ def _default_help_command(ctx, *commands : str):
         for key in commands[1:]:
             try:
                 key = _mention_pattern.sub(repl, key)
-                command = command.commands.get(key)
+                command = command.all_commands.get(key)
                 if command is None:
                     yield from destination.send(bot.command_not_found.format(key))
                     return
@@ -564,7 +564,7 @@ class BotBase(GroupMixin):
                 self.remove_cog(cogname)
 
         # first remove all the commands from the module
-        for command in self.commands.copy().values():
+        for command in self.all_commands.copy().values():
             if command.module is lib:
                 command.module = None
                 if isinstance(command, GroupMixin):
@@ -676,7 +676,7 @@ class BotBase(GroupMixin):
         invoker = view.get_word()
         ctx.invoked_with = invoker
         ctx.prefix = invoked_prefix
-        ctx.command = self.commands.get(invoker)
+        ctx.command = self.all_commands.get(invoker)
         return ctx
 
     @asyncio.coroutine
diff --git a/discord/ext/commands/core.py b/discord/ext/commands/core.py
index b335e87ba..71d5ff4be 100644
--- a/discord/ext/commands/core.py
+++ b/discord/ext/commands/core.py
@@ -589,16 +589,21 @@ class GroupMixin:
 
     Attributes
     -----------
-    commands : dict
+    all_commands: dict
         A mapping of command name to :class:`Command` or superclass
         objects.
     """
     def __init__(self, **kwargs):
-        self.commands = {}
+        self.all_commands = {}
         super().__init__(**kwargs)
 
+    @property
+    def commands(self):
+        """Set[:class:`Command`]: A unique set of commands without aliases that are registered."""
+        return set(self.all_commands.values())
+
     def recursively_remove_all_commands(self):
-        for command in self.commands.copy().values():
+        for command in self.all_commands.copy().values():
             if isinstance(command, GroupMixin):
                 command.recursively_remove_all_commands()
             self.remove_command(command.name)
@@ -629,14 +634,14 @@ class GroupMixin:
         if isinstance(self, Command):
             command.parent = self
 
-        if command.name in self.commands:
+        if command.name in self.all_commands:
             raise discord.ClientException('Command {0.name} is already registered.'.format(command))
 
-        self.commands[command.name] = command
+        self.all_commands[command.name] = command
         for alias in command.aliases:
-            if alias in self.commands:
+            if alias in self.all_commands:
                 raise discord.ClientException('The alias {} is already an existing command or alias.'.format(alias))
-            self.commands[alias] = command
+            self.all_commands[alias] = command
 
     def remove_command(self, name):
         """Remove a :class:`Command` or subclasses from the internal list
@@ -655,7 +660,7 @@ class GroupMixin:
             The command that was removed. If the name is not valid then
             `None` is returned instead.
         """
-        command = self.commands.pop(name, None)
+        command = self.all_commands.pop(name, None)
 
         # does not exist
         if command is None:
@@ -667,12 +672,12 @@ class GroupMixin:
 
         # we're not removing the alias so let's delete the rest of them.
         for alias in command.aliases:
-            self.commands.pop(alias, None)
+            self.all_commands.pop(alias, None)
         return command
 
     def walk_commands(self):
         """An iterator that recursively walks through all commands and subcommands."""
-        for command in tuple(self.commands.values()):
+        for command in tuple(self.all_commands.values()):
             yield command
             if isinstance(command, GroupMixin):
                 yield from command.walk_commands()
@@ -699,13 +704,13 @@ class GroupMixin:
         """
 
         names = name.split()
-        obj = self.commands.get(names[0])
+        obj = self.all_commands.get(names[0])
         if not isinstance(obj, GroupMixin):
             return obj
 
         for name in names[1:]:
             try:
-                obj = obj.commands[name]
+                obj = obj.all_commands[name]
             except (AttributeError, KeyError):
                 return None
 
@@ -769,7 +774,7 @@ class Group(GroupMixin, Command):
 
         if trigger:
             ctx.subcommand_passed = trigger
-            ctx.invoked_subcommand = self.commands.get(trigger, None)
+            ctx.invoked_subcommand = self.all_commands.get(trigger, None)
 
         if early_invoke:
             injected = hooked_wrapped_callback(self, ctx, self.callback)
diff --git a/discord/ext/commands/formatter.py b/discord/ext/commands/formatter.py
index c0ac67818..5c9fff2f4 100644
--- a/discord/ext/commands/formatter.py
+++ b/discord/ext/commands/formatter.py
@@ -171,7 +171,7 @@ class HelpFormatter:
         """int : Returns the largest name length of a command or if it has subcommands
         the largest subcommand name."""
         try:
-            commands = self.command.commands if not self.is_cog() else self.context.bot.commands
+            commands = self.command.all_commands if not self.is_cog() else self.context.bot.all_commands
             if commands:
                 return max(map(lambda c: len(c.name) if self.show_hidden or not c.hidden else 0, commands.values()))
             return 0
@@ -265,7 +265,7 @@ class HelpFormatter:
             except CommandError:
                 return False
 
-        iterator = self.command.commands.items() if not self.is_cog() else self.context.bot.commands.items()
+        iterator = self.command.all_commands.items() if not self.is_cog() else self.context.bot.all_commands.items()
         if self.show_check_failure:
             return filter(sane_no_suspension_point_predicate, iterator)