I think it's not "fundamentally different". Type info is there in the code, it's just much more implicit and requires much more work to extract and use. One thing which does just this is Jedi project (for python) and it's absolutely astonishing how much data you can get out of it!
Also I think that dynamic languages were meant to run inside a dynamic environment. For example in Pharo Smalltalk (probably all Smalltalks) every single piece of metadata is runtime data. Static analysis has no sense, because in Pharo there is no "static" at all - everything happens inside a living environment and (for example) as soon as you write a method it's turned into CompiledMethod object which has all the data about the method you would ever need for you to query easily. Good luck implementing better refactoring tools than those in Smalltalk for any other language.
Essentially the same approach is used in Emacs Lisp. For example, if you see a function you don't recognize, you can jump to it's definition. The thing here is that Emacs doesn't know where the definition is because of static analysis - it just has this compiled chunk of code in memory which happens to have a name you're looking for. This chunk of code knows a location of it's definition and many other pieces of metadata which are all available on runtime. It of course doesn't work if the function isn't already loaded into Emacs.
Most statically typed languages retain almost no type data in runtime. Most dynamically typed languages have almost no type data on compile time. I see this as largely equivalent.
So I guess what I want to say is that there is no fundamental difference in what the dynamic and static languages are, but there is (and should be) a very fundamental difference in how they are used. Choosing the between the two is I think almost exclusively a matter of preference. A good programmer should feel comfortable with both, though.
Also I think that dynamic languages were meant to run inside a dynamic environment. For example in Pharo Smalltalk (probably all Smalltalks) every single piece of metadata is runtime data. Static analysis has no sense, because in Pharo there is no "static" at all - everything happens inside a living environment and (for example) as soon as you write a method it's turned into CompiledMethod object which has all the data about the method you would ever need for you to query easily. Good luck implementing better refactoring tools than those in Smalltalk for any other language.
Essentially the same approach is used in Emacs Lisp. For example, if you see a function you don't recognize, you can jump to it's definition. The thing here is that Emacs doesn't know where the definition is because of static analysis - it just has this compiled chunk of code in memory which happens to have a name you're looking for. This chunk of code knows a location of it's definition and many other pieces of metadata which are all available on runtime. It of course doesn't work if the function isn't already loaded into Emacs.
Most statically typed languages retain almost no type data in runtime. Most dynamically typed languages have almost no type data on compile time. I see this as largely equivalent.
So I guess what I want to say is that there is no fundamental difference in what the dynamic and static languages are, but there is (and should be) a very fundamental difference in how they are used. Choosing the between the two is I think almost exclusively a matter of preference. A good programmer should feel comfortable with both, though.