Phrases like "static typing" and "dynamic typing" are thrown around a lot, and people tend to use subtly different definitions, so let's start by clarifying what we mean.
Consider a language that has static types that are checked at compile-time. But say that a type error generates only a non-fatal warning, and at runtime, everything is duck-typed. These static types are only for the programmer's convenience, and do not affect the codegen. This illustrates that static typing does not by itself impose any limitations, and is not mutually exclusive with dynamic typing. (Objective-C is a lot like this.)
But most static type systems do not behave this way. There's two common properties of static type systems that can impose limitations:
The compiler may reject a program that contains a static type error.
This is a limitation because many type safe programs necessarily contain a static type error.
For example, I have a Python script that needs to run as both Python 2 and Python 3. Some functions changed their parameter types between Python 2 and 3, so I have code like this:
if sys.version_info[0] == 2:
wfile.write(txt)
else:
wfile.write(bytes(txt, 'utf-8'))
A Python 2 static type checker would reject the Python 3 code (and vice versa), even though it would never be executed. My type safe program contains a static type error.
As another example, consider a Mac program that wants to run on OS X 10.6, but take advantage of new features in 10.7. The 10.7 methods may or may not exist at runtime, and it's on me, the programmer, to detect them. A static type checker is forced to either reject my program to ensure type safety, or accept the program, along with the possibility of producing a type error (function missing) at runtime.
Static type checking assumes that the runtime environment is adequately described by the compile time information. But predicting the future is perilous!
Here's one more limitation:
The compiler may generate code that assumes the runtime type is the static type.
Assuming the static types are "correct" provides many opportunities for optimization, but these optimizations can be limiting. A good example is proxy objects, e.g. remoting. Say you wish to have a local proxy object that forwards method invocations to a real object in another process. It would be nice if the proxy were generic (so it can masquerade as any object) and transparent (so that existing code does not need to know it is talking to a proxy). But to do this, the compiler cannot generate code that assumes the static types are correct, e.g. by statically inlining method calls, because that will fail if the object is actually a proxy.
Examples of such remoting in action include ObjC's NSXPCConnection or C#'s TransparentProxy (whose implementation required a few pessimizations in the runtime - see here for a discussion).
When the codegen is not dependent on the static types, and you have facilities like message forwarding, you can do lots of cool stuff with proxy objects, debugging, etc.
So that's a sampling of some of the stuff you can do if you are not required to satisfy a type checker. The limitations are not imposed by static types, but by enforced static type checking.